Skip to content

fix(schema-compiler): resolve multi_stage order_by template in owning cube context#10858

Open
tlangton3 wants to merge 1 commit into
cube-js:masterfrom
tlangton3:cube/fix-tesseract-multistage-orderby-view-alias
Open

fix(schema-compiler): resolve multi_stage order_by template in owning cube context#10858
tlangton3 wants to merge 1 commit into
cube-js:masterfrom
tlangton3:cube/fix-tesseract-multistage-orderby-view-alias

Conversation

@tlangton3
Copy link
Copy Markdown
Contributor

Summary

A multi_stage: true measure whose order_by.sql template references another measure by bare name (e.g. {num_parcels}) crashes Cube at schema-compile time when queried through a view that doesn't expose the referenced member under its bare name — either not at all, or only under an alias. The crash presents as a generic TypeError: Cannot read properties of undefined (reading '_objectWithResolvedProperties') from BaseQuery.evaluateSql.

The referenced member is a cube-internal implementation detail of the rank — it doesn't need to be (and shouldn't be) exposed on every view that includes the rank. The Rust planner already follows this semantic; this PR brings the JS schema-compiler in line.

Fixes #10856.

Changes

  • packages/cubejs-schema-compiler/src/compiler/CubeSymbols.tsgenerateIncludeMembers now tags view-generated measure definitions that carry an orderBy template with orderByCubeName (the underlying cube's name from the include path).
  • packages/cubejs-schema-compiler/src/adapter/BaseQuery.jsevaluateSymbolSql uses symbol.orderByCubeName when evaluating the order_by template, falling back to cubeName for direct cube access. evaluateSql now throws a clear UserError when cubeEvaluator.resolveSymbol returns undefined, replacing the unguarded _objectWithResolvedProperties access.
  • packages/cubejs-schema-compiler/test/unit/multi-stage-orderby-view-alias.test.ts — new regression test exercising the production shape (view exposes the rank + a time dim, rank's order_by references a cube measure not included on the view).

Implementation Details

The bug surfaced in the JS schema-compiler. CubeSymbols.generateIncludeMembers (the path that builds the view's exposed measure symbols from underlying cube members) was propagating the rank's orderBy template as raw text onto the view's generated definition, losing the "this template was authored on cube X" context. Then at query time, BaseQuery.evaluateSymbolSql evaluated the template against the consumer's queried cubeName (the view), calling resolveSymbol(viewName, name). When the bare name wasn't a key in the view's symbol table — because the view stores aliased members under their alias key, not the original name — the lookup returned undefined, and the next line accessed ._objectWithResolvedProperties without a guard.

TimeDimensionSymbol-style implicit suffixing isn't involved here; this is purely a name-not-present-on-the-view resolution gap.

The Rust planner (rust/cube/cubesqlplanner/cubesqlplanner/src/planner/symbols/measure_symbol.rs:544-550) already compiles order_by at schema-compile time in path.cube_name() — the owning cube. The crash fires earlier in JS schema validation, before Tesseract takes over for SQL generation.

The fix carries orderByCubeName through to the view-generated symbol so evaluateSql can pass it as the resolution context, matching the Rust behaviour. Falls back to cubeName for direct cube access (where the view path doesn't apply). Scoped narrowly to orderByfilters, case, etc. weren't surfaced in the reported repro and aren't included in this patch.

The defensive guard on BaseQuery.js:3593 is hygiene: even with the substantive fix, an unguarded ._objectWithResolvedProperties on undefined is a latent footgun. Any future resolution failure now surfaces a clear UserError naming the missing symbol and the cube it was looked up against.

Testing

  • yarn tsc (cubejs-schema-compiler) — clean.
  • npx jest --no-coverage --testPathPattern='dist/test/unit/multi-stage-orderby-view-alias' — passes.
  • npx jest --no-coverage dist/test/unit/views.test.js dist/test/unit/postgres-query.test.js dist/test/unit/hierarchies.test.js — 25/25 passes (no regressions in adjacent areas).
  • New multi-stage-orderby-view-alias.test.ts verified to fail on master with the documented TypeError and pass after the fix; the generated SQL contains the cube's parcels column in the rank's ORDER BY.
    EOF

… cube context

When a multi_stage measure (e.g. type: rank) is exposed through a view,
its order_by template — which references other cube members by bare
name — was being evaluated against the view's symbol table rather than
the underlying cube's. If the view didn't expose the referenced member
under its bare name (either not at all, or only under an alias), the
resolver returned undefined and BaseQuery.evaluateSql crashed at the
unguarded _objectWithResolvedProperties access with:

  TypeError: Cannot read properties of undefined (reading
  '_objectWithResolvedProperties')

The referenced member is a cube-internal implementation detail of the
rank — it doesn't need to be (and shouldn't be) exposed on every view
that includes the rank.

Fix:
- CubeSymbols.generateIncludeMembers now tags view-generated measure
  definitions that carry an order_by template with orderByCubeName
  (the underlying cube's name), so the consumer of the symbol knows
  where the template's references were authored.
- BaseQuery.evaluateSymbolSql uses symbol.orderByCubeName (falling
  back to cubeName for direct cube access) when evaluating the
  order_by template, matching the Rust planner's semantic of compiling
  measure templates in the owning cube's context.
- BaseQuery.evaluateSql now throws a clear UserError when
  cubeEvaluator.resolveSymbol returns undefined, instead of leaving
  an unguarded _objectWithResolvedProperties access to surface as a
  generic TypeError.

Adds a regression test exercising the production shape: a view that
exposes only the rank + a time dim, with the rank's order_by
referencing a cube measure not exposed on the view.

Fixes cube-js#10856.
@github-actions github-actions Bot added javascript Pull requests that update Javascript code pr:community Contribution from Cube.js community members. labels May 11, 2026
@tlangton3 tlangton3 marked this pull request as ready for review May 11, 2026 17:16
@tlangton3 tlangton3 requested a review from a team as a code owner May 11, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update Javascript code pr:community Contribution from Cube.js community members.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-stage measure order_by template crashes when queried through a view that doesn't expose the referenced member by its bare name

1 participant