feat(query): M2M existence tests — the two-hop correlation path#321
Closed
0x054 wants to merge 1 commit into
Closed
feat(query): M2M existence tests — the two-hop correlation path#3210x054 wants to merge 1 commit into
0x054 wants to merge 1 commit into
Conversation
t.tags.exists(...) works on many-to-many relations, bare, scoped, and ~-negated, spelled and behaving exactly like the reverse-FK form (ADR-0007: one verb at every cardinality and relation kind). The same exists node carries a two-hop correlation path — join table first, correlated to the enclosing scope, then the target — and the existing Rust render loop covers it unchanged: no new render mechanism, proving the design's claim that M2M is test surface, not a second mechanism. - build_reverse_specs maps M2M descriptors to join-table specs; each side's descriptor already orients source_col/target_col for that side, so both the declaring and the related_name side spell identically. - The proxy builds hops from the spec: join_table.source_col against the root PK, then target on join_table.target_col = target.pk. The inner lambda resolves over the M2M target with full predicate power (operators, combinators, negation, cross-scope guard) — the #315 machinery, untouched. - Hand-authored golden vector pins the 2-hop shape, asserted from the Python emitter and the Rust decoder; a Rust render test pins join-table-FROM + inner-join-target + last-hop-alias qualification. - e2e on both backends: bare (each root exactly once regardless of how many join rows match), scoped, negated, both sides of the relation, root-predicate/count composition, and the proxy's single-verb error surfaces. Refs #311, #316
This was referenced Jul 18, 2026
Contributor
Author
|
Superseded by #323 (slices 2–4 combined into one rebase-mergeable PR; content identical). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #316
Stacked on #320 (slice 2/4); base retargets as the stack merges.
Slice 3/4 of the existence-tests PRD (#311, ADR-0007):
.exists()on many-to-many relations, bare, scoped, and~-negated — spelled and behaving exactly like the reverse-FK form.What ships
renders
related_nameside spell identically).&/|/~, the cross-scope guard — all thefeatExistence tests 2/4: scoped inner predicates — forward traversal, nesting, cross-scope guard #315 machinery, untouched.Acceptance criteria (#316)
~-negated.exists()on an M2M relation, e2e on both backendsTesting
cargo test: 196 + 28 (ferro-schema-ir) passed, including the 2-hop render test and vector round-trippytest --db-backends=sqlite,postgres: 1668 passed (full matrix, local Postgres)ty checkandruff check: clean