TML-2794: M:N slice 5 — PSL authors many-to-many (junction → N:M + through)#819
TML-2794: M:N slice 5 — PSL authors many-to-many (junction → N:M + through)#819tensordreams wants to merge 7 commits into
Conversation
…ce-scoped) Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
…ations A bare backrelation list field whose target pairs with the current model through an explicit junction model (composite @@id columns exactly the FK columns of the two N:1 relations) now lowers to a navigable relation with cardinality N:M and a populated through descriptor, matching the shape the TS builder emits for rel.manyToMany. The junction model and any direct FK-side matches keep their existing 1:N/N:1 output untouched; lists with no recognisable junction keep the PSL_ORPHANED_BACKRELATION_LIST diagnostic, and structurally ambiguous junction pairings (e.g. unnamed self-referential lists) report PSL_AMBIGUOUS_BACKRELATION_LIST. TML-2794 Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
Junction recognition accepted any child FK regardless of what it referenced, while downstream consumers pair through.childColumns positionally against the target model id columns. A child FK referencing a non-id unique, or a composite id in swapped order, was recognised but emitted a silently wrong join. Require the child FK to reference exactly the target model full id and carry its junction columns in target-id order; anything else falls back to the orphaned-backrelation diagnostic. The parent side stays as-is: its pairing runs through the FK own parallel localFields/parentColumns arrays and is order-safe by construction (pinned by the swapped-order test). Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
…er_tags) Mirror the TS-builder M:N fixture in PSL: an explicit UserTag junction model with composite @@id over its two FK columns plus bare backrelation list fields on User and Tag. The emitted contract carries cardinality N:M with a populated through descriptor on both sides -- shape-identical to what rel.manyToMany produces -- proving the PSL explicit-junction lowering round-trips the canonical emit + validate pipeline. Generated artifacts come from the canonical CLI emit (prisma-next contract emit --config .../mn-psl/prisma-next.config.ts) and re-emit byte-identically, following the polymorphism fixture convention. Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
…xture Drive the PSL-emitted M:N contract through the full ORM API with one representative integration case per surface: include (explicit select + implicit default selection), some/none/every relation filters, and connect/disconnect/nested-create junction writes -- mirroring the TS-fixture coverage in mn-include / mn-filter / mn-nested-write. Deserializing the emitted JSON runs the full sql contract validation pipeline, so the suite also pins that a PSL-authored N:M + through contract round-trips validation. The runtime is built against the mn-psl contract (storageHash differs from the base fixture), following the polymorphism-fixture contractOverride pattern. Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
The mn-psl PSL fixture config was not emitted by the package emit script, so fixtures:check was vacuously green for it and a PSL interpreter regression would leave the committed contract.json stale. Append the mn-psl contract emit alongside the polymorphism fixture; no cp step needed since the fixture emits into its own generated dir. Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
size-limit report 📦
|
@prisma-next/extension-author-tools
@prisma-next/mongo-runtime
@prisma-next/family-mongo
@prisma-next/sql-runtime
@prisma-next/family-sql
@prisma-next/extension-arktype-json
@prisma-next/middleware-cache
@prisma-next/mongo
@prisma-next/extension-paradedb
@prisma-next/extension-pgvector
@prisma-next/extension-postgis
@prisma-next/postgres
@prisma-next/sql-orm-client
@prisma-next/sqlite
@prisma-next/extension-supabase
@prisma-next/target-mongo
@prisma-next/adapter-mongo
@prisma-next/driver-mongo
@prisma-next/contract
@prisma-next/utils
@prisma-next/config
@prisma-next/errors
@prisma-next/framework-components
@prisma-next/operations
@prisma-next/ts-render
@prisma-next/contract-authoring
@prisma-next/ids
@prisma-next/psl-parser
@prisma-next/psl-printer
@prisma-next/cli
@prisma-next/cli-telemetry
@prisma-next/emitter
@prisma-next/migration-tools
prisma-next
@prisma-next/vite-plugin-contract-emit
@prisma-next/mongo-codec
@prisma-next/mongo-contract
@prisma-next/mongo-value
@prisma-next/mongo-contract-psl
@prisma-next/mongo-contract-ts
@prisma-next/mongo-emitter
@prisma-next/mongo-schema-ir
@prisma-next/mongo-query-ast
@prisma-next/mongo-orm
@prisma-next/mongo-query-builder
@prisma-next/mongo-lowering
@prisma-next/mongo-wire
@prisma-next/sql-contract
@prisma-next/sql-errors
@prisma-next/sql-operations
@prisma-next/sql-schema-ir
@prisma-next/sql-contract-psl
@prisma-next/sql-contract-ts
@prisma-next/sql-contract-emitter
@prisma-next/sql-lane-query-builder
@prisma-next/sql-relational-core
@prisma-next/sql-builder
@prisma-next/target-postgres
@prisma-next/target-sqlite
@prisma-next/adapter-postgres
@prisma-next/adapter-sqlite
@prisma-next/driver-postgres
@prisma-next/driver-sqlite
commit: |
Slice 5 of the SQL ORM: Many-to-Many End to End project (follow-on group). Refs TML-2794.
Overview
PSL could not author a navigable many-to-many relation: the relation resolver emitted only
N:1/1:N, and a bare list field (tags Tag[]) with no FK pair was diagnosed asPSL_ORPHANED_BACKRELATION_LIST—cardinality: 'N:M' + throughexisted only via the TS contract builder. This PR teaches the PSL interpreter explicit-junction recognition (form 1, pinned at pickup): when a bare list field has a recognisable junction model — composite@@id([a, b])covering exactly the FK columns of twoN:1relations to the two side models — the list lowers to a navigableN:Mrelation through that junction, shape-identical torel.manyToManyoutput.Changes
psl-relation-resolution.ts: junction recognition in the previously-orphaned branch —findJunctionFkPairs+ id-coverage gate +manyToManyRelationNode; child FK must reference the target's full id (set-equal),through.childColumnsreordered to id order (the runtime joinschildColumns[i] = targetColumns[i]by index); decline → existing orphaned diagnostic. Self-referential M:N disambiguated by the list's@relationname (pins the parent-side FK); unnamed symmetric lists get the ambiguity diagnostic. Surrogate-id join models are deliberately not recognised. Direct FK matches still win (stay1:N).interpreter.relations.many-to-many.test.ts): both directions, composite keys, swapped-order FK references, self-referential, diagnostic preservation,validateContractround-trip.fixtures/mn-psl/(User ↔ Tagviauser_tags, mirroring the TS fixture) wired into the sql-orm-client emit pipeline sofixtures:checkregenerates and diffs it.mn-psl-parity.test.ts: 8 integration tests proving the full M:N ORM API (include explicit+implicit,some/none/every, connect, disconnect, nested create) against the PSL-emitted contract.Why
The PG demo emits its contract from PSL, so it cannot show the M:N API until PSL can author it (slice 6 is blocked on this). Form 1 was chosen over Prisma-style implicit lists as the smallest surface that matches the existing diagnostic's guidance; implicit lists remain a clean follow-up.
Scope
PSL authoring layer + fixtures/tests only. No sql-orm-client runtime changes, no TS-builder changes, no demo changes (slice 6). Implicit-list authoring (form 2) deliberately excluded.