Mongo PSL: bare-member enums fail interpretation unless enum inference codecs are wired explicitly#934
Mongo PSL: bare-member enums fail interpretation unless enum inference codecs are wired explicitly#934ankur-arch wants to merge 6 commits into
Conversation
A bare-member enum (`enum Direction { INBOUND OUTBOUND }`) in a Mongo PSL
schema failed contract interpretation with PSL_ENUM_CANNOT_INFER_TYPE
cascading into PSL_UNSUPPORTED_FIELD_TYPE on every enum-typed field,
unless the config passed enumInferenceCodecs explicitly — only
@prisma-next/mongo's defineConfig did.
The interpreter now derives the default inference codecs from the
target-contributed PSL String/Int scalar type descriptors, so every
config surface resolves classic enums identically; the explicit option
still overrides. defineConfig drops its now-redundant wiring.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Ankur Datta <64993082+ankur-arch@users.noreply.github.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe Mongo PSL interpreter now derives enum inference codec ids from target scalar descriptors when explicit configuration is absent. Mongo extension wiring is simplified, documentation is updated, and unit and CLI integration tests cover inference, overrides, diagnostics, and emitted contracts. ChangesEnum inference codec defaulting
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant PrismaSchema
participant Interpreter as interpretPslDocumentToMongoContract
participant ScalarDescriptors
participant EnumEntity
participant ContractJson
PrismaSchema->>Interpreter: parse enum and model fields
Interpreter->>ScalarDescriptors: derive enum inference codecs
ScalarDescriptors-->>Interpreter: String and Int codec ids
Interpreter->>EnumEntity: resolve enum type and value set
EnumEntity-->>Interpreter: enum contract metadata
Interpreter->>ContractJson: emit domain and storage enum structures
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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/config-loader
@prisma-next/emitter
@prisma-next/language-server
@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: |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.enums.test.ts (1)
152-166: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOptional: add coverage for the derived
intcodec path.Current tests cover default text-codec inference, explicit override, and failure when
Intis missing, but no test exercises an integer bare-member enum successfully resolving via the derivedintcodec end-to-end.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.enums.test.ts` around lines 152 - 166, Add a test in interpreter.enums.test.ts to cover the successful derived int codec path for bare-member enums. Extend the existing enum inference coverage around interpretPslDocumentToMongoContract by creating an int-valued enum case that resolves through the derived int codec end-to-end, then assert the resulting namespace enum codecId matches the expected mongo/int32@1 codec. Use the existing test helpers and symbols like bareMemberEnumSchema, mongoScalarTypeDescriptors, mongoCodecLookup, authoringContributions, and UNBOUND_NAMESPACE_ID to keep it aligned with the current enum inference tests.test/integration/test/cli.emit-command.additional.test.ts (1)
383-417: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSplit the combined
toMatchObjectinto targeted assertions.This single
toMatchObjectbundlestargetFamily,target, and deeply nested enum/model/field checks. Based on learnings, this repo's test convention is to prefer separateexpect()assertions per field overtoMatchObject()for multi-field validation, since it produces clearer, more actionable failure messages pinpointing exactly which field failed.♻️ Example split
- expect(contractJson).toMatchObject({ - targetFamily: 'mongo', - target: 'mongo', - domain: { - namespaces: { - __unbound__: { - enum: { - WhatsAppMessageDirection: { - codecId: 'mongo/string@1', - members: [ - { name: 'INBOUND', value: 'INBOUND' }, - { name: 'OUTBOUND', value: 'OUTBOUND' }, - ], - }, - }, - models: { - WhatsAppMessages: expect.objectContaining({ - fields: expect.objectContaining({ - direction: { - type: { kind: 'scalar', codecId: 'mongo/string@1' }, - nullable: false, - valueSet: { - plane: 'domain', - entityKind: 'enum', - namespaceId: '__unbound__', - entityName: 'WhatsAppMessageDirection', - }, - }, - }), - }), - }, - }, - }, - }, - }); + expect(contractJson.targetFamily).toBe('mongo'); + expect(contractJson.target).toBe('mongo'); + const enumEntry = + contractJson.domain.namespaces.__unbound__.enum.WhatsAppMessageDirection; + expect(enumEntry.codecId).toBe('mongo/string@1'); + expect(enumEntry.members).toEqual([ + { name: 'INBOUND', value: 'INBOUND' }, + { name: 'OUTBOUND', value: 'OUTBOUND' }, + ]); + const field = + contractJson.domain.namespaces.__unbound__.models.WhatsAppMessages.fields.direction; + expect(field.type).toEqual({ kind: 'scalar', codecId: 'mongo/string@1' }); + expect(field.nullable).toBe(false); + expect(field.valueSet).toEqual({ + plane: 'domain', + entityKind: 'enum', + namespaceId: '__unbound__', + entityName: 'WhatsAppMessageDirection', + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/integration/test/cli.emit-command.additional.test.ts` around lines 383 - 417, The test in the contract JSON assertion is using one large toMatchObject for multiple unrelated checks, which should be split into focused expect() assertions. Update the assertions around contractJson to validate targetFamily, target, and the nested domain/namespace/enum/model/field structure separately, using the existing WhatsAppMessageDirection and WhatsAppMessages references to keep each failure message precise.Source: Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.enums.test.ts`:
- Around line 152-166: Add a test in interpreter.enums.test.ts to cover the
successful derived int codec path for bare-member enums. Extend the existing
enum inference coverage around interpretPslDocumentToMongoContract by creating
an int-valued enum case that resolves through the derived int codec end-to-end,
then assert the resulting namespace enum codecId matches the expected
mongo/int32@1 codec. Use the existing test helpers and symbols like
bareMemberEnumSchema, mongoScalarTypeDescriptors, mongoCodecLookup,
authoringContributions, and UNBOUND_NAMESPACE_ID to keep it aligned with the
current enum inference tests.
In `@test/integration/test/cli.emit-command.additional.test.ts`:
- Around line 383-417: The test in the contract JSON assertion is using one
large toMatchObject for multiple unrelated checks, which should be split into
focused expect() assertions. Update the assertions around contractJson to
validate targetFamily, target, and the nested domain/namespace/enum/model/field
structure separately, using the existing WhatsAppMessageDirection and
WhatsAppMessages references to keep each failure message precise.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: d517c9fa-2aeb-423c-b314-080ef7179670
📒 Files selected for processing (6)
packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.tspackages/2-mongo-family/2-authoring/contract-psl/src/provider.tspackages/2-mongo-family/2-authoring/contract-psl/test/interpreter.enums.test.tspackages/3-extensions/mongo/src/config/define-config.tstest/integration/test/cli.emit-command.additional.test.tstest/integration/test/fixtures/cli/cli-integration-test-app/fixtures/emit-command/prisma-next.config.mongo-define.ts
|
Follow-up for the second issue in the same Discord thread (extendable |
…nce default wiring Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Ankur Datta <64993082+ankur-arch@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Ankur Datta <64993082+ankur-arch@users.noreply.github.com>
|
Ponytail review (lazy-senior-dev ladder over the diff):
→ skipped: same defaulting for the SQL PSL interpreter — add if/when a SQL user hits the equivalent report (its defineConfig paths already wire the ids). |
…ference-defaults Signed-off-by: Ankur Datta <64993082+ankur-arch@users.noreply.github.com>
Refresh pass — merged
|
| Check | Result |
|---|---|
pnpm build |
✅ 68/68 |
pnpm typecheck |
✅ 143/143 |
pnpm lint |
✅ 82/82 |
pnpm lint:deps |
✅ no violations |
@prisma-next/mongo-contract-psl tests |
✅ 155/155 |
| Integration suite | ✅ except one pre-existing flake, below |
The one integration failure is test/sql-orm-client/nested-includes-strategy.test.ts (portal "C_12" does not exist, a PGlite/pg-protocol flake) — unrelated to this diff, which touches no SQL code.
Verification of the core claim
The removed defineConfig wiring is behaviour-identical for Mongo, confirmed against the real adapter descriptors (packages/3-mongo-target/2-mongo-adapter/src/exports/control.ts:25):
String→mongo/string@1=MONGO_STRING_CODEC_IDInt→mongo/int32@1=MONGO_INT32_CODEC_ID
So deriving from the scalar type descriptors reproduces exactly what defineConfig passed by hand, and it now also covers the mongoContract()-direct and LSP interpret paths.
Deliberate scope decision: SQL is not fixed here
A review pass flagged that prismaContract has the same missing default (packages/3-extensions/supabase/prisma-next.config.ts:12 is a live victim) and suggested lifting the derivation into framework-components/authoring for both families. I did not do that, because for SQL it is not behaviour-preserving:
- postgres scalar descriptors map
Int→pg/int4@1(packages/3-targets/6-adapters/postgres/src/core/control-mutation-defaults.ts:158) - postgres
defineConfigwiresenumInferenceCodecs.int→PG_INT_CODEC_ID=pg/int@1(packages/3-extensions/postgres/src/config/define-config.ts:51)
Applying the same derivation on the SQL side would silently shift int-backed enum inference from pg/int@1 to pg/int4@1. That discrepancy looks like a latent bug in its own right and deserves a separate, deliberately-scoped PR rather than a drive-by in a Mongo fix. (String → pg/text@1 does match PG_TEXT_CODEC_ID; only the int leg diverges.)
Remaining risks / for human review
- The misleading cascade is narrowed, not removed. When no default can be derived, a field typed by the failed enum still reports
PSL_UNSUPPORTED_FIELD_TYPEon top ofPSL_ENUM_CANNOT_INFER_TYPE— pinned by the third test ininterpreter.enums.test.ts. Suppressing the field-level diagnostic when the enum itself already failed would be the real fix; out of scope here. - Derivation is all-or-nothing: a target declaring
Stringbut notIntinfers neither, because the option type is a single{ text, int }pair. No real target hits this. - SQL follow-up above needs an owner and a decision on which int codec is correct.
- Test scaffolding in
interpreter.enums.test.tsduplicates fixtures that three other test files in the package also hand-roll. The SQL sibling package has a sharedtest/fixtures.ts; Mongo doesn't. Extracting one is a worthwhile cleanup but was left out to keep this PR reviewable.
main has bumped to 0.15.0, so check:upgrade-coverage now requires per-PR declarations in 0.15-to-0.16/instructions.md. The entry was recorded against the already-shipped 0.14-to-0.15 cycle. Signed-off-by: Ankur Datta <64993082+ankur-arch@users.noreply.github.com>
…ference-defaults Signed-off-by: Ankur Datta <64993082+ankur-arch@users.noreply.github.com> # Conflicts: # skills/extension-author/prisma-next-extension-upgrade/upgrades/0.15-to-0.16/instructions.md
What this fixes
Using an enum in a MongoDB PSL schema failed contract resolution:
Reported on Discord ([NEXT], 2026-07-07). After this PR, a plain enum just works, on every config surface:
What was broken
An enum without
@@type(...)infers its codec from its members — but the codec ids to infer to were only wired in one place:@prisma-next/mongo'sdefineConfig. Any config that used themongoContract()provider directly hitPSL_ENUM_CANNOT_INFER_TYPE, which then cascaded into the misleadingPSL_UNSUPPORTED_FIELD_TYPEon every field typed by the enum — exactly the reported "2 of 2" diagnostics.The fix
The Mongo PSL interpreter now derives the default inference codecs from the target's own scalar type descriptors (
String→mongo/string@1,Int→mongo/int32@1) — the same valuesdefineConfigpassed by hand.defineConfigdrops its now-redundant wiring, and the explicitenumInferenceCodecsoption still overrides.packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts— derive the default when the input omitsenumInferenceCodecspackages/3-extensions/mongo/src/config/define-config.ts— remove the duplicate wiringskills/extension-author/.../0.14-to-0.15/instructions.md— no-action upgrade declaration (behaviour identical for extension authors)Testing
Tests were written first and failed for the right reason, then went green:
interpreter.enums.test.ts): a bare-member enum resolves with no explicit wiring (domain enum + typed field + storage value set); an explicitenumInferenceCodecsstill overrides; the original diagnostic pair is still reported when no default can be derived.contract emitwith both config styles — rawmongoContract()(previously failing) and@prisma-next/mongodefineConfig(new fixture).pnpm test:packagessweep, the integration emit suite,pnpm lint:deps, andpnpm fixtures:check(no fixture drift) all pass.The same Discord thread's second ask — an extendable
Collectionclass for the Mongo ORM — is shipped separately in #936.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
StringandIntscalar type descriptors.enumInferenceCodecsremains supported as an override.Bug Fixes
Documentation
Tests