feat(query): existence-test error surfaces and docs — the feature's edges#322
Closed
0x054 wants to merge 1 commit into
Closed
feat(query): existence-test error surfaces and docs — the feature's edges#3220x054 wants to merge 1 commit into
0x054 wants to merge 1 commit into
Conversation
…dges Every remaining surface where a reverse or M2M relation can be named now answers with the supported spelling, and the docs teach existence tests end to end. Error surfaces beyond the proxy's own (those shipped in the tracer bullet): - join()/left_join() on a reverse/M2M edge stays rejected — the pinned "a join never multiplies root rows" property is preserved by rejection, not implicit DISTINCT — with the error naming .exists() (previously an opaque "must return a relation path" TypeError). - in_() with a query RHS stays a TypeError whose message names the existence test when the RHS is a query (the #307 repro's second guess); a non-query RHS keeps the plain message. - include() rejection verified unchanged for M2M edges too — population remains a separate future mechanism. Docs: - New guide section "Existence Tests on Reverse & Many-to-Many Relations": real models (Assignment + Annotated tabs), lambda-style predicates throughout, rendered SQL for the #307/#308 shapes, the explicit grouping contrast, negation, traversal-inside-the-test, nesting, M2M, the loud dead ends, and the exists-test vs query-terminal disambiguation. Backed by two new runnable example scripts exercised by the docs harness. - Operators table gains the .exists() row; the forward existence/absence section and the reverse-relation filtering section cross-link the reverse direction. - Reference (api/queries.md) states the one-verb rule and its rejections. - Roadmap and "Not Yet Supported" now distinguish reverse predicates (shipped — the existence test) from reverse population (still future; the include() rejection stays), and track cross-scope correlation as #309. Refs #311, #317
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 #317, closes #311, closes #307, closes #308
Stacked on #321 (slice 3/4); base retargets as the stack merges. Final slice of the existence-tests PRD (#311, ADR-0007) — when this merges, the PRD and the originating Pinch PRDs (#307, #308) close.
Error surfaces
Every remaining place a reverse or M2M relation can be named now answers with the supported spelling:
join()/left_join()on a reverse/M2M edge stays rejected — the pinned "a join never multiplies root rows" property is preserved by rejection, not implicit DISTINCT — and the error now names.exists()(previously the opaque generic "must return a relation path"). Pinned for reverse-FK, M2M, and both join verbs.in_()with a query RHS stays aTypeError, and the message now names the existence test when the RHS is aQuery/ProjectedQuery(thefeatReverse-relation membership predicates: EXISTS from the root query (PRD from Pinch) #307 repro's second guess:t.id.in_(subquery)). A non-query RHS keeps the plain message — no hint where none applies.in_(subquery)remains declined, not deferred (ADR-0007).include()rejection verified unchanged for M2M edges too — population stays a separate future mechanism; membership filtering and population remain distinct axes.Docs
featReverse-relation membership predicates: EXISTS from the root query (PRD from Pinch) #307is_transfershape and thefeatOR-composition across a left-joined reverse child table (PRD from Pinch) #308 line-aware category filter, the explicit grouping contrast (exists(A & B)vsexists(A) & exists(B)), negation, forward traversal inside the subquery, nesting, M2M from both sides, the loud dead ends, and the exists-test vsawait query.exists()terminal disambiguation. Backed by two runnable example scripts (existence_tests.py+ annotated twin) exercised by the docs-example harness..exists(...)row; the forward existence/absence section and the instance-side reverse-relation section cross-link the reverse direction.api/queries.md) states the one-verb rule and its rejections.include()rejection stays), and track cross-scope correlation asfeatCross-scope correlation in existence tests (deferred from ADR-0007) #309.Acceptance criteria (#317)
left_join()on a reverse/M2M edge raises naming.exists()(pinned by test)in_()with a query RHS raises naming.exists()(pinned by test)include()on a reverse/M2M edge unchanged (existing rejection verified by test)Testing
pytest --db-backends=sqlite,postgres: 1679 passed (full matrix, local Postgres), including the new pinned error surfaces and both docs example scriptsty checkandruff check: clean