feat: v1.7.0 -> master#11042
Conversation
|
Claude finished @ovr's task in 59s —— View job Code Review — v1.7.0 release / Elasticsearch driver removalOne-line headline: LGTM — clean removal of the deprecated Elasticsearch driver. 0 high, 0 medium, 1 low. Full review (click to expand)Checklist
SummaryThis PR removes the What I verified
FindingsLow — Removed redirects will now 404 instead of redirecting
Nits
Not reviewed
|
|
Claude finished @ovr's task in 38s —— View job Code Review — v1.7.0 release / Elasticsearch driver removalOne-line headline: LGTM — clean removal of the deprecated Elasticsearch driver. 0 high, 0 medium, 1 low. (Re-affirmed: no new commits since the prior review — HEAD is still Full review (click to expand)Checklist
SummaryThis PR removes the What I verified
FindingsLow — Removed redirects will now 404 instead of redirecting
Nits
Not reviewed
• Branch: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #11042 +/- ##
===========================================
+ Coverage 58.75% 83.64% +24.88%
===========================================
Files 217 256 +39
Lines 17392 79018 +61626
Branches 3524 0 -3524
===========================================
+ Hits 10219 66091 +55872
- Misses 6659 12927 +6268
+ Partials 514 0 -514
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
BREAKING CHANGE: The Elasticsearch driver has been removed. It was deprecated in v1.6.0. There is no drop-in replacement.
…11044) BREAKING CHANGE: The running_total measure type has been removed. Data models that use `type: running_total` will now fail validation. Replace them with a rolling_window measure using an unbounded trailing window.
…iable (#11048) BREAKING CHANGE: The CUBEJS_SCHEDULED_REFRESH_CONCURRENCY environment variable has been removed. It was deprecated in v1.2.7. Use CUBEJS_SCHEDULED_REFRESH_QUERIES_PER_APP_ID instead.
BREAKING CHANGE: The `renewQuery` parameter of the `/v1/load` REST endpoint and the GraphQL `cube` query has been removed. Use the `cache` parameter instead: `cache: 'must-revalidate'` replaces `renewQuery: true`, and the default `stale-if-slow` replaces `renewQuery: false`.
BREAKING CHANGE: The context_to_roles (contextToRoles) configuration option has been removed. It was deprecated in v1.6.4. Use context_to_groups (contextToGroups) instead.
BREAKING CHANGE: CreateOptions.dbType has been removed. Use driverFactory instead.
Node.js 20 reached EOL on April 30, 2026; Node.js 22 is in maintenance mode since October 21, 2025. The minimal supported version is now 22.
Toolkit has a dependecy on @achrinza/node-ipc that blocks migration for new Node.js everytime. More funny, that it still doesn't support Node.js 26, which I wan to declare in testing matrix. We don't define any .vue files, that's why we can use babel without anything especiall, moreover we build this package outside it folder. We define config in the root directory for rollup bundler # Conflicts: # yarn.lock
…parser babel-eslint has been deprecated since 2020 and was only resolving via hoisting from the legacy vue-cli toolkit until it was dropped. Use the maintained @babel/eslint-parser instead and declare it explicitly in both packages that reference it.
BREAKING CHANGE: Users who install custom Python packages into the Cube image (e.g. for Python/Jinja data models) must target Python 3.13. Packages built for 3.11 will not load.
BREAKING CHANGE: The -jdk image now runs Java 21. JDBC drivers and custom JARs must be compatible with OpenJDK 21.
…fault Tesseract is now the default SQL planner. CUBEJS_TESSERACT_SQL_PLANNER defaults to true (TS env + Rust cubesql config); explicitly disabling it falls back to the legacy planner and emits a one-time deprecation warning, since the legacy planner will be removed in the near future. Tesseract pre-aggregation planning is no longer independently configurable: the CUBEJS_TESSERACT_PRE_AGGREGATIONS env var is dropped, and pre-aggregation planning now follows CUBEJS_TESSERACT_SQL_PLANNER. BaseQuery still honors neverUseSqlPlannerPreaggregation() so CubeStoreQuery stays opted out for correctness (HLL/multi-stage).
Tesseract deserialized filter `values` as `Vec<Option<String>>`, so a
boolean (or numeric) value in a query filter — e.g.
`{operator: 'equals', values: [true]}` — failed with
"invalid type: boolean `true`, expected a string". The legacy JS planner
never hit this since JS is untyped.
Introduce a typed `FilterValue { Str, Bool, Num, Null }` enum and thread it
end-to-end (deserialization → TypedFilter → scalar operators → param
rendering). Values are normalized to their canonical string form only at
the `allocate_param` boundary, so the param channel stays `Vec<String>`.
A dependency-free member-expression measure such as `count(*)`, in a
query with no dimensions or filters to seed the join, resolved an empty
join-hint set. That path calls `JoinGraph.buildJoin([])`, which returns
null, and the Rust bridge then fails to deserialize the missing
`JoinDefinitionStatic` ("invalid type: unit value, expected struct
JoinDefinitionStatic").
In the multi-fact join grouping, fall back to the measure's own cube when
its hint set is empty — but only for real, joinable cubes. View members
are left untouched: their join comes from the other query members, and
the view itself is not a joinable cube.
A measure exposed through a view is a reference wrapper whose declared `type` is collapsed to `number` (a Calculated kind), hiding the real aggregation. PatchMeasure then rejected ad-hoc CASE-WHEN filters with "Unsupported additional filters for measure ... type number", because Calculated measures don't support additional filters. Resolve the reference chain to the owning cube measure before patching, so the filter is pushed inside the real aggregation (`SUM(CASE WHEN ... END)`), matching the legacy planner's `patchMeasurePushDownFilterSql`. `resolve_reference_chain` is a no-op for plain cube measures, so non-view PatchMeasure behaviour is unchanged.
The SQL API encodes grouped join push-downs (e.g. `JOIN (SELECT ... GROUP BY ... ORDER BY ... LIMIT n) t ON ...`) as a `subqueryJoins` entry on the query. Only the legacy planner consumed it (via `customSubQueryJoins`); `buildSqlAndParamsRust` dropped it before the native call and Tesseract had no way to receive it. As a result the joined sub-query was omitted entirely: queries returned unfiltered rows (the inner LIMIT/ORDER vanished) and projections referencing the sub-query alias failed with "missing FROM-clause entry". Thread `subqueryJoins` end to end: - BaseQuery.js: pass `subqueryJoins` into both native queryParams. - New `SubqueryJoin` bridge (sql/joinType/alias + `on` member expression). - QueryPropertiesCompiler compiles each `on` into a `SqlCall`; stored on QueryProperties as `LogicalSubqueryJoinItem`s. - SimpleQueryPlanner folds them into the query's LogicalJoin. - Physical builder emits them as `SingleSource::RawSubquerySql` joins; the no-join fast path now also checks `subquery_joins` so alias-only projections still materialize the join. The opaque sub-query SQL (incl. its ORDER BY/LIMIT) is emitted verbatim, so top-N semantics are preserved. The SQL API sends the join alias pre-quoted and references it verbatim in the ON condition, so the raw sub-query source is emitted with its alias as-is (no re-quoting). Changes are gated on a non-empty `subquery_joins`, leaving existing plans untouched.
In a wrapped SQL-API query, cubesql pushes a grouped CubeScan whose
granularized time-dimension column it references by an explicit alias,
sent via `memberToAlias` keyed `{member}.{granularity}` (e.g.
`orders.created_at.month` -> `datetrunc_utf8__`). Regular dimensions and
measures already honor this override, but `TimeDimensionSymbol` computed
its alias as `{base alias}_{granularity}` (`orders__created_at_month`)
and ignored the override. The wrapper then referenced a column the
CubeScan never emitted -> `column "datetrunc_utf8__" does not exist`.
Look up the `memberToAlias` override for the granularized member in
`compile_time_dimensions` and pass it through a new
`TimeDimensionSymbol::new_with_alias`. When no override is present the
alias is unchanged, so non-pushdown queries are unaffected.
The legacy planner wraps SQL generation in compiler.withQuery() so JS extensions can resolve compiler.contextQuery() during member-SQL evaluation. The Tesseract path (buildSqlAndParamsRust) skipped this, so extensions like Funnels/RefreshKeys hit `contextQuery()` undefined when the native planner calls back into JS.
A masked aggregate measure whose conditional row-level mask filter references a dimension that is in the GROUP BY crashed the native planner with "Measure filter node processor called for wrong node". `MaskedSqlNode::resolve_mask` rendered the mask filter through `self.input` — the measure processor chain (`CaseSqlNode -> MeasureFilterSqlNode -> ...`). When the filter evaluated a dimension reference it reached `MeasureFilterSqlNode`, which only accepts measures and errored. Build a second, kind-dispatching "unmasked" processor tree (a `RootSqlNode` with masking disabled via a new `skip` flag) and render the mask filter through it, so a dimension reference routes through the dimension chain and a filter member that is itself masked does not recurse — mirroring the legacy planner's `skipMasking` behaviour in `conditionalMemberMaskSql`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A boolean (or numeric) `securityContext` / `userAttributes` value used in
SQL — e.g. a mask `CASE WHEN {securityContext.cubeCloud.userAttributes.x}` —
is allocated as a raw scalar param by the context-symbols proxy. The native
planner deserialized `getAllocatedParams()` as `Vec<String>`, so the value
failed with "invalid type: boolean `true`, expected a string".
Deserialize allocated params as `FilterValue` and normalize them to their
canonical string form at the `query_tools` boundary, keeping the param
channel `Vec<String>` — extending the typed-value handling introduced for
filter values in 9b7bb5b.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OracleQuery only overrode legacy-planner methods (asSyntaxTable, groupByDimensionLimit, groupByClause), so the native planner fell back to the generic templates and produced invalid Oracle: `AS` before table / subquery aliases, `LIMIT`, and positional `GROUP BY`. Add `sqlTemplates()` overrides so the native planner emits Oracle-compatible SQL: no `AS` before aliases (query_aliased + FROM subquery), expression-based GROUP BY, and `OFFSET ... ROWS FETCH NEXT ... ROWS ONLY`. Update the unit tests for the native planner: drive row limiting via `rowLimit` (the option the planner reads — the native planner applies no default limit), and accept the planner's quoted subquery aliases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anner The native (Tesseract) planner — now the default — emits semantically equivalent SQL with different formatting from the legacy planner. Update the expectations accordingly: - single-line SQL with the planner's whitespace (e.g. `FROM t AS "t"`, `ORDER BY 2 ASC`) in base-query syntax-sugar and join tests; - fewer wrapping parens in FILTER_PARAMS / FILTER_GROUP substitutions (`(type = ?)` vs `((type = ?))`); - quoted subquery aliases (`AS "q_0"`); - multi-granularity auto-order emits every granularity column (result- equivalent to the legacy min-granularity-only ordering); - MSSQL rolling-window queries group by the calculated-granularity expression instead of a time-series CTE alias. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e-agg dates The native planner computes pre-aggregation partition ranges eagerly during matching, calling `inDbTimeZone`. When the query has no timezone this hit `localTimestampToUtc(undefined, ...)` and threw "Unknown timezone: undefined" (the legacy planner is lazy and never reached it). Default to UTC so a timezone-less query can still match/describe partitioned pre-aggregations. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…he pre-agg The native pre-aggregation matcher only rejected multiplied measures when the query itself was multiplied, so a query for an unmultiplied measure (e.g. `orders.total_qty`) wrongly matched a pre-aggregation that multiplies it by grouping on a joined cube's dimension — the stored value differs. This ports the JS planner's #9541 rejection. Add `MultiFactJoinGroups::multiplied_measures()` and reject a match when a used measure is multiplied in the pre-aggregation but not in the query. The query's multiplicativity is computed filter-aware (a multiplying filter, like a multi-stage measure, makes the multiplied pre-agg a legitimate match), matching the JS `hasMultipliedMeasures` gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When reading a rollupLambda pre-aggregation, each union member's SELECT
referenced dimension columns as `{member_table_cube}__{name}`. For a dimension
from a joined cube (e.g. `Users.name` in an `Orders` pre-agg) that yielded a
wrong, non-existent column name, dropping it from the union. Reference each
stored column by the dimension's own member alias instead, which is correct for
both same-cube and cross-cube dimensions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
No description provided.