Skip to content

fix: preserve preagg + canonical backend through with_measures on joins#261

Open
hussainsultan wants to merge 1 commit intomainfrom
hussain/fix/grain-mismatch-with-measures
Open

fix: preserve preagg + canonical backend through with_measures on joins#261
hussainsultan wants to merge 1 commit intomainfrom
hussain/fix/grain-mismatch-with-measures

Conversation

@hussainsultan
Copy link
Copy Markdown
Collaborator

Summary

  • ops.py: SemanticJoin.with_measures() / with_dimensions() wraps the join in a SemanticTableOp with name=None. Pre-agg partitioning used all_roots = [wrapper], so prefixed aggregates collapsed into the unprefixed bucket and bypassed per-grain pre-aggregation — fanning out the coarser table by the finer table's row count. Fix: partition by _find_all_root_models(join_op) instead.
  • expr.py: to_untagged() / to_tagged() returned expressions that raised XorqError: Multiple backends found on .execute(), even though SemanticTable.execute() worked (it already wraps with _rebind_to_canonical_backend). Apply the same rebind inside to_untagged(); to_tagged() benefits transitively.

Test plan

  • 941 tests pass (1 pre-existing unrelated failure excluded)
  • expr.execute(), to_untagged(expr).execute(), to_tagged(expr).execute() all return correct numbers for grain-matched and grain-mismatched joins

🤖 Generated with Claude Code

SemanticJoin.with_measures()/with_dimensions() wraps the joined table in a
new SemanticTableOp with name=None. _to_untagged_with_preagg partitioned
aggregates via _partition_agg_specs_by_source(plan.agg_specs, all_roots)
where all_roots = [wrapper_op]; since the wrapper has no name, prefixed
aggregates collapsed into the unprefixed bucket and bypassed per-grain
pre-aggregation, fanning out the coarser table's measures.

Partition by _find_all_root_models(join_op) instead, recovering the
original per-table roots from the SemanticJoinOp. For non-wrapper paths
this is equivalent to all_roots; only the wrapper case changes behavior.

Also: to_untagged() now applies _rebind_to_canonical_backend so callers
of to_untagged()/to_tagged() get expressions that .execute() directly.
SemanticTable.execute()/.compile()/.sql() already did this rebind; the
public conversion functions did not, surfacing "Multiple backends found"
errors on join + preagg lowering. to_tagged() benefits transitively.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant