TML-2884: Add domain enums to Mongo — author, $jsonSchema enforce, typed read#834
Conversation
|
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:
📝 WalkthroughWalkthroughThis PR adds shared enum authoring primitives, lowers enums through Mongo contract building and PSL interpretation, and exposes unbound enum accessors at runtime for Mongo and SQLite. ChangesEnum authoring pipeline
Sequence Diagram(s)sequenceDiagram
participant Author as Contract author
participant Builder as buildContractFromDefinition
participant Interp as interpretPslDocumentToMongoContract
participant Client as mongo() / MongoClient
Author->>Builder: defineContract({ enums, models })
Builder->>Builder: validate enum names and build builtEnums
Builder-->>Author: contract.domain.namespaces.__unbound__.enum
Author->>Interp: PSL document + authoringContributions
Interp->>Interp: processEnumDeclarations
Interp->>Interp: resolve fields with enumCodecIds
Interp->>Interp: deriveJsonSchema(builtEnums)
Interp-->>Author: lowered Mongo contract
Author->>Client: connect contract
Client->>Client: buildUnboundEnums(contract.domain)
Client-->>Author: db.enums.Role accessors
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
@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: |
size-limit report 📦
|
Review-response roundAddressing your two review comments + the local code-review findings that surfaced when I ran Your review comments
Other in-scope work since the original pushWhen I ran Test rigor + integration evidence (D6, 5 commits):
Architectural cleanup (D7, 4 commits):
Gate
Known follow-up not in this PRThe F07 ORM-write test still carries one The D5 honesty correction: my original framing of "consumers' apps will run out of stack space" overstated immediate urgency. The refactor is the right shape but motivated by parity-with-SQL and forward-looking scaling, not a currently-firing failure. |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.ts (1)
1894-1899:⚠️ Potential issue | 🟠 Major | ⚡ Quick winFactory-returned
enumsare currently dropped during contract assembly.In the factory path,
buildBoundContractmergesmodels,valueObjects, androots, but notenums. Anyenumsproduced by the factory are silently ignored beforebuildContractFromDefinition(...), so authored enum declarations can be lost at runtime.💡 Proposed fix
type ContractFactory< Models extends Record<string, AnyModelBuilder> = Record<never, never>, ValueObjects extends Record<string, AnyValueObjectBuilder> = Record<never, never>, Roots extends Record<string, ModelNameInput> | undefined = undefined, @@ > = (helpers: ContractAuthoringHelpers<Family, Target, ExtensionPacks>) => { readonly models?: Models; readonly valueObjects?: ValueObjects; readonly roots?: Roots; + readonly enums?: Record<string, EnumTypeHandle>; }; @@ const Built extends { readonly models?: Record<string, AnyModelBuilder>; readonly valueObjects?: Record<string, AnyValueObjectBuilder>; readonly roots?: Record<string, ModelNameInput> | undefined; + readonly enums?: Record<string, EnumTypeHandle>; }, @@ return buildContractFromDefinition({ ...full, ...ifDefined('models', built.models), ...ifDefined('valueObjects', built.valueObjects), ...ifDefined('roots', built.roots), + ...ifDefined('enums', built.enums), });🤖 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-ts/src/contract-builder.ts` around lines 1894 - 1899, The `buildBoundContract` function is not including `enums` when merging the factory-produced contract properties. In the return statement of `buildBoundContract`, add a spread operation for `built.enums` using the same `ifDefined` pattern as the existing spreads for `models`, `valueObjects`, and `roots`. This will ensure that enum definitions produced by the factory are preserved and passed to `buildContractFromDefinition` instead of being silently dropped.
🧹 Nitpick comments (1)
packages/2-mongo-family/1-foundation/mongo-contract/test/contract-types.test-d.ts (1)
16-18: ⚡ Quick winRemove the decorative section banner comments in this test file.
These headings are redundant with the test names and can be dropped to keep the file aligned with the repo’s TS comment policy.
As per coding guidelines,
Don't add comments if avoidable, prefer code that expresses its intent.Also applies to: 411-416
🤖 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/1-foundation/mongo-contract/test/contract-types.test-d.ts` around lines 16 - 18, Remove the decorative section banner comments from the test file that serve only as visual separators and are redundant with the test names and code structure they precede. Specifically, delete the multi-line comment blocks (including the dashes) that introduce sections like the enum value-union narrowing tests. Apply this removal to all such decorative section headers throughout the file, including the locations mentioned in the review comment, to align with the coding guideline that avoids unnecessary comments in favor of code that expresses its own intent.Source: Coding guidelines
🤖 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.
Inline comments:
In
`@packages/1-framework/1-core/framework-components/src/shared/framework-authoring.ts`:
- Around line 939-943: Replace the bare `as` cast in the factory variable
assignment with `blindCast` to comply with the repository's cast policy. The
factory variable is currently being cast using the bare `as` operator to a
function type that accepts input and ctx parameters; instead, wrap the
descriptor.output.factory expression with a blindCast call (which is already
imported) to perform the type cast, keeping the same function type signature for
the cast target.
In `@packages/1-framework/2-authoring/contract/src/enum-type.ts`:
- Around line 31-40: The `member()` function uses the nullish coalescing
operator `??` which treats both `undefined` and `null` as missing values,
causing a type/runtime mismatch when `null` is explicitly passed. Fix this by
changing the value assignment logic to only use `name` as the default when
`value` is strictly `undefined` (parameter omitted), while allowing `null` to be
passed through unchanged. Replace `value ?? name` with a conditional check like
`value === undefined ? name : value` to distinguish between omitted parameters
and explicitly provided `null` values.
In `@packages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.ts`:
- Line 151: The FieldBuilder interface needs to be made generic to preserve the
EnumTypeHandle's type parameters. Add a type parameter to FieldBuilder (likely
EnumHandle or similar) to carry the Handle's type information, make __enumHandle
non-optional and properly typed as EnumHandle, and ensure that
createFieldBuilder returns FieldBuilder with the correct handle type argument.
Additionally, update the return types of the .optional() and .many() methods on
FieldBuilder to preserve the handle's type parameters when chaining, so that
BuilderEnumValueUnion can correctly extract literal enum values from the generic
__enumHandle constraint.
In
`@packages/2-mongo-family/2-authoring/contract-ts/test/enum-type.authoring.test.ts`:
- Around line 127-143: The test for rejecting empty enum members is not isolated
because the malformed object is missing multiple required contract fields, so
the validation failure could be due to those missing fields rather than the
empty members array specifically. Create a valid baseline contract object that
passes MongoContractSchema validation, then create a second test object that is
identical except with enum.Role.members set to an empty array [], and verify
that only this second object fails validation. This ensures the test
specifically validates the enum-members rule rather than other validation
failures.
---
Outside diff comments:
In `@packages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.ts`:
- Around line 1894-1899: The `buildBoundContract` function is not including
`enums` when merging the factory-produced contract properties. In the return
statement of `buildBoundContract`, add a spread operation for `built.enums`
using the same `ifDefined` pattern as the existing spreads for `models`,
`valueObjects`, and `roots`. This will ensure that enum definitions produced by
the factory are preserved and passed to `buildContractFromDefinition` instead of
being silently dropped.
---
Nitpick comments:
In
`@packages/2-mongo-family/1-foundation/mongo-contract/test/contract-types.test-d.ts`:
- Around line 16-18: Remove the decorative section banner comments from the test
file that serve only as visual separators and are redundant with the test names
and code structure they precede. Specifically, delete the multi-line comment
blocks (including the dashes) that introduce sections like the enum value-union
narrowing tests. Apply this removal to all such decorative section headers
throughout the file, including the locations mentioned in the review comment, to
align with the coding guideline that avoids unnecessary comments in favor of
code that expresses its own intent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 02e7c6ea-b6bd-4dc7-bcd4-f2fbb945acd3
⛔ Files ignored due to path filters (3)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlprojects/enums-as-domain-concept/slices/mongo-enums-end-to-end/plan.mdis excluded by!projects/**projects/enums-as-domain-concept/slices/mongo-enums-end-to-end/spec.mdis excluded by!projects/**
📒 Files selected for processing (36)
packages/1-framework/0-foundation/contract/src/enum-accessor.tspackages/1-framework/0-foundation/contract/src/exports/enum-accessor.tspackages/1-framework/1-core/framework-components/src/shared/framework-authoring.tspackages/1-framework/2-authoring/contract/package.jsonpackages/1-framework/2-authoring/contract/src/enum-type.tspackages/1-framework/2-authoring/contract/src/index.tspackages/2-mongo-family/1-foundation/mongo-contract/src/contract-schema.tspackages/2-mongo-family/1-foundation/mongo-contract/src/contract-types.tspackages/2-mongo-family/1-foundation/mongo-contract/test/contract-types.test-d.tspackages/2-mongo-family/2-authoring/contract-psl/package.jsonpackages/2-mongo-family/2-authoring/contract-psl/src/derive-json-schema.tspackages/2-mongo-family/2-authoring/contract-psl/src/exports/index.tspackages/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/derive-json-schema.test.tspackages/2-mongo-family/2-authoring/contract-psl/test/interpreter.enum.test.tspackages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.tspackages/2-mongo-family/2-authoring/contract-ts/src/enum-type.tspackages/2-mongo-family/2-authoring/contract-ts/src/exports/contract-builder.tspackages/2-mongo-family/2-authoring/contract-ts/test/enum-type.authoring.test.tspackages/2-mongo-family/2-authoring/contract-ts/test/enum-type.test-d.tspackages/2-mongo-family/9-family/src/core/authoring-entity-types.tspackages/2-mongo-family/9-family/src/core/control-descriptor.tspackages/2-mongo-family/9-family/src/exports/pack.tspackages/2-mongo-family/9-family/test/control.test.tspackages/2-sql/2-authoring/contract-psl/src/interpreter.tspackages/2-sql/2-authoring/contract-ts/src/enum-type.tspackages/3-extensions/mongo/package.jsonpackages/3-extensions/mongo/src/contract/enum-type.tspackages/3-extensions/mongo/src/exports/contract-builder.tspackages/3-extensions/mongo/src/runtime/mongo.tspackages/3-extensions/mongo/test/mongo.enum.e2e.test.tspackages/3-extensions/mongo/test/mongo.test.tspackages/3-extensions/mongo/test/mongo.types.test-d.tspackages/3-extensions/postgres/package.jsonpackages/3-extensions/sqlite/src/runtime/sqlite.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.ts (1)
1360-1368:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject enum-typed fields that reference undeclared enums
Line 1361 stamps
valueSetfor any enum-handle field, but enum entities are only emitted fromdefinition.enums. There is no validation that all referenced handles are declared, so contracts can contain dangling enum references.Please validate referenced enum names against the declared enum map during build and throw a deterministic authoring error on missing declarations.
Also applies to: 1757-1788
🤖 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-ts/src/contract-builder.ts` around lines 1360 - 1368, The buildContractField function creates a valueSet reference for enum-handle fields without validating that the referenced enum is actually declared in the contract definition. Add validation in the condition where builder.__enumHandle exists to check that the enum name (builder.__enumHandle.enumName) is declared in the available enum map, and throw a deterministic authoring error if the enum declaration is missing. Only create and assign the valueSet object if the referenced enum is validated to exist.
♻️ Duplicate comments (1)
packages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.ts (1)
142-154:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftPreserve enum handle generics through
FieldBuildersonamedType()keeps literal unions
namedType()passes a concrete handle, butcreateFieldBuilderreturns a non-handle-genericFieldBuilder, so the handle’sValuestuple gets erased.BuilderEnumValueUnionthen cannot reliably recover the enum value union, and type narrowing falls back to base codec output.Suggested direction
-export interface FieldBuilder< +export interface FieldBuilder< Type extends ContractFieldType = ContractFieldType, Nullable extends boolean = boolean, Many extends boolean = boolean, + EnumHandle extends EnumTypeHandle | undefined = undefined, > { readonly __kind: 'field'; readonly __type: Type; readonly __nullable: Nullable; readonly __many: Many; - readonly __enumHandle?: EnumTypeHandle; - optional(): FieldBuilder<Type, true, Many>; - many(): FieldBuilder<Type, Nullable, true>; + readonly __enumHandle?: EnumHandle; + optional(): FieldBuilder<Type, true, Many, EnumHandle>; + many(): FieldBuilder<Type, Nullable, true, EnumHandle>; }-function createFieldBuilder< +function createFieldBuilder< Type extends ContractFieldType, Nullable extends boolean, Many extends boolean, + EnumHandle extends EnumTypeHandle | undefined = undefined, >( spec: FieldBuilderSpec<Type, Nullable, Many>, - enumHandle?: EnumTypeHandle, -): FieldBuilder<Type, Nullable, Many> { + enumHandle?: EnumHandle, +): FieldBuilder<Type, Nullable, Many, EnumHandle> {Also applies to: 616-623, 838-845, 943-957
🤖 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-ts/src/contract-builder.ts` around lines 142 - 154, The FieldBuilder interface does not preserve the enum handle as a generic parameter, causing the handle's Values tuple to be erased when createFieldBuilder returns a non-handle-generic FieldBuilder. This prevents BuilderEnumValueUnion from recovering the enum value union reliably. Add a new generic parameter to the FieldBuilder interface (e.g., EnumHandle) to preserve the specific enum handle type, update the optional() and many() methods to propagate this generic parameter through their return types, and ensure that when namedType() passes a concrete handle, the handle information is retained through the builder chain. Apply the same generic preservation pattern at the other affected sites: lines 616-623, 838-845, and 943-957, ensuring consistency across all FieldBuilder usage.
🤖 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.
Outside diff comments:
In `@packages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.ts`:
- Around line 1360-1368: The buildContractField function creates a valueSet
reference for enum-handle fields without validating that the referenced enum is
actually declared in the contract definition. Add validation in the condition
where builder.__enumHandle exists to check that the enum name
(builder.__enumHandle.enumName) is declared in the available enum map, and throw
a deterministic authoring error if the enum declaration is missing. Only create
and assign the valueSet object if the referenced enum is validated to exist.
---
Duplicate comments:
In `@packages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.ts`:
- Around line 142-154: The FieldBuilder interface does not preserve the enum
handle as a generic parameter, causing the handle's Values tuple to be erased
when createFieldBuilder returns a non-handle-generic FieldBuilder. This prevents
BuilderEnumValueUnion from recovering the enum value union reliably. Add a new
generic parameter to the FieldBuilder interface (e.g., EnumHandle) to preserve
the specific enum handle type, update the optional() and many() methods to
propagate this generic parameter through their return types, and ensure that
when namedType() passes a concrete handle, the handle information is retained
through the builder chain. Apply the same generic preservation pattern at the
other affected sites: lines 616-623, 838-845, and 943-957, ensuring consistency
across all FieldBuilder usage.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: cd6f6a55-4738-4289-814c-12e4ff2eb30b
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
packages/1-framework/0-foundation/contract/src/enum-accessor.tspackages/1-framework/2-authoring/contract/src/enum-type.tspackages/2-mongo-family/2-authoring/contract-psl/package.jsonpackages/2-mongo-family/2-authoring/contract-ts/src/contract-builder.tspackages/2-mongo-family/2-authoring/contract-ts/test/contract-builder.types.test-d.tspackages/3-extensions/mongo/package.jsonpackages/3-extensions/mongo/test/mongo.enum.e2e.test.tspackages/3-extensions/mongo/test/mongo.types.test-d.tstest/integration/test/mongo/interpreter.enum.test.ts
💤 Files with no reviewable changes (2)
- packages/2-mongo-family/2-authoring/contract-psl/package.json
- packages/3-extensions/mongo/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/3-extensions/mongo/test/mongo.types.test-d.ts
- packages/3-extensions/mongo/test/mongo.enum.e2e.test.ts
R2 review-response round (D9)R2 surfaced 9 findings (3 architect + 6 PE). 7 fixed in-scope this round; 2 deferred with reasons. Fixed (5 commits)
Deferred (with reasons)
Honesty corrections from the synthesis
Final gate
|
Typed write input (R5) — closing the last R10 parity gap (D10)R10 promises "R4/R5 parity" for the Mongo client. R4 (typed output) landed in D8; R5 (typed input) was unmet — What landed
Root cause found beyond the briefD8's "output narrowing works" was partially false on the TS-DSL builder path: the enum handle lived on an optional Honest caveat —
|
9d9628a to
73a6929
Compare
|
Addressing CodeRabbit review R1 (PRR_kwDOQM0QJc8AAAABDJwahw) sub-items:
|
|
Addressing CodeRabbit review R2 (PRR_kwDOQM0QJc8AAAABDLQDCQ) sub-items:
|
ec1febb to
17df144
Compare
…chema acceptance - Add `enum-type.ts` to `@prisma-next/mongo-contract-ts` with full `enumType`/`member`/`bindEnumType`/`isEnumTypeHandle` implementation (mirrors the SQL family's enum-type.ts; mongo domain cannot import sql) - Export `bindEnumType`, `enumType`, `member`, `EnumTypeHandle`, `EnumMember`, `ExtractCodecTypesFromPack` from `@prisma-next/mongo-contract-ts/contract-builder` - Add `field.namedType(handle)` to the Mongo builder, carrying `__enumHandle` through the `optional()`/`many()` chain - Add `enums?` slot to `ContractDefinition` and `BoundDefinitionInput` - `buildContractFromDefinition` accumulates enums into `domain.namespaces[__unbound__].enum` and stamps the field's domain `valueSet` ref (`plane:'domain'`, `entityKind:'enum'`, `namespaceId:'__unbound__'`) - Add `ContractEnumSchema` and `DomainEnumRefSchema` to the Mongo contract schema; add `enum?` to the domain namespace slot and `valueSet?` to `RawFieldSchema` so built enum contracts pass arktype validation - Add `3-extensions/mongo/src/contract/enum-type.ts` binding `bindEnumType<MongoCodecTypes>()` from `@prisma-next/mongo-contract-ts`; export `enumType` and `member` from `@prisma-next/mongo/contract-builder` - New round-trip test: author → build → validate → assert enum entity + field valueSet ref + MongoContractSchema passes - New type-test: `enumType` handle `.values` is a literal readonly tuple Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
- New `authoring-entity-types.ts` in `family-mongo` exports `mongoFamilyEnumEntityDescriptor`, `mongoFamilyEntityTypes`, and `mongoFamilyPslBlockDescriptors` (mirrors SQL family's pattern). - `pack.ts` and `control-descriptor.ts` now expose the authoring section so the PSL provider and CLI can discover enum block descriptors. - Mongo PSL `interpreter.ts` gains `authoringContributions` input, `processEnumDeclarations` (routes enum blocks through the entity factory), enum-aware field resolution (stamps `valueSet` ref), and includes `enum:` in the returned domain namespace. - `provider.ts` passes `pslBlockDescriptors` to the parser and `authoringContributions` to the interpreter. - `interpreter.enum.test.ts` proves PSL → contract round-trip parity with D1's TS DSL output (enum entity shape + field valueSet ref). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
When a field carries a domain valueSet ref with entityKind:'enum', fieldToBsonSchema() now adds `enum: [...member values]` (declaration order) to the derived property schema. The existing validationLevel:'strict' means the collection validator rejects any out-of-set write. - derive-json-schema.ts: added `enums` parameter to fieldToBsonSchema / deriveObjectSchema / deriveJsonSchema / derivePolymorphicJsonSchema - interpreter.ts: passes builtEnums through both deriveJsonSchema and derivePolymorphicJsonSchema call sites - derive-json-schema.test.ts: five new tests covering enum array presence, absence on non-enum fields, nullable enum, declaration-order preservation, and unknown-enum graceful skip Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
- array enum field (many:true): inject `enum` into `items`, not the outer schema - nullable enum field: include `null` in the emitted `enum` array so null writes pass $jsonSchema - correct existing nullable enum test to assert the fixed shape - add tests: array enum, nullable+array enum Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
InferFieldType gains a valueSet branch that resolves enum fields to their literal value union (nullable / many preserved). MongoClient interface and facade both carry readonly enums: NamespacedEnums<TContract>, wired via buildNamespacedEnums + blindCast mirroring Postgres exactly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
db.enums.Role now works directly on MongoClient — no __unbound__ key needed. Mirrors sqlite's UnboundEnums + unboundNamespace pattern: - Added UnboundEnums<TContract> type alias (projects out UNBOUND_NAMESPACE_ID) - Added unboundNamespace() helper (duplicated from sqlite; both are target- internal, so no cross-family import and no invasive lift required) - MongoClient.enums is now UnboundEnums<TContract> instead of NamespacedEnums - Runtime enums built via unboundNamespace(buildNamespacedEnums(...)) - Type tests and runtime tests updated: __unbound__ indirection removed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Will Madden <madden@prisma.io> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ests Adds the MMS-backed integration test and emit-then-consume type test that prove the full vertical: author → $jsonSchema enforcement → typed read → db.enums. Covers scalar, nullable, and array enum fields. Out-of-set writes are rejected by the MongoDB collection validator; in-set writes round-trip. The emit-then-consume tests assert value-union narrowing through the emitted contract.d.ts (non-vacuous: falls back to codec channel when narrowing is absent). Adds @prisma-next/emitter and @prisma-next/mongo-emitter as devDependencies to @prisma-next/mongo. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…Cast The namedType field builder used a bare object cast to narrow the literal kind string. Replace with blindCast to satisfy the no-bare-cast ratchet (delta was +1; now 0). Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Add DefinitionEnums / EnumHandleAccessorType / BuiltEnumAccessors to the
Mongo TS DSL builder and hang `enumAccessors: BuiltEnumAccessors<Definition>`
off MongoContractBaseFromDefinition, mirroring SQL's approach. The slot is
type-only (the blindCast at the builder's return preserves the runtime shape
satisfying MongoContract); BuiltEnumAccessorsOf picks it up so
NamespacedEnums resolves db.enums.<Name>.values to the literal tuple for
TS-DSL-authored contracts.
Add the proof in mongo.types.test-d.ts: a defineContract({enums:{Role}})
contract resolves db.enums.Role.values to readonly ['user','admin'] and
db.enums.Role.members.User to "user" without any cast.
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ent dual carrier (F12/A07)
F12 replaces the vacuous `const _: T | undefined = undefined` parity probe with
a non-vacuous ExtractMongoFieldOutputTypes reachability assertion and a typed
namespace-enum-slot test that fails if F14's slot is removed. The precise
per-field narrowing through BuilderFieldOutputType is covered by the F11 test
in contract-builder.types.test-d.ts (where the inner defineContract resolves
the typemaps reliably).
A07 rewrites the dual-carrier comment in enum-accessor.ts. With F14 typing the
namespace `enum?` slot, the runtime accessor builds via `buildNamespacedEnums`
read the same shape on both producers. enumAccessors (now optional on
MongoContractBaseFromDefinition) remains as the literal-tuple carrier for
`db.enums.Role.values[0]` — tuple structure can't survive the namespace path
because ContractEnum stores members as an array of {name, value}, not a
positional tuple. NamespaceEnumAccessors selects the enumAccessors carrier
when present, otherwise the namespace enum entries, avoiding the type
intersection that would conflict literal-tuple values against the union.
The F14 cast removal in mongo.enum.e2e.test.ts: the RuntimeNs cast is gone;
`ns?.enum` is read directly and only narrows the codec-value JsonValue
relationship at the deriveJsonSchema boundary.
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…tom (A09)
D7's enum-type.ts lift used `Symbol('EnumTypeHandle')` as the nominal brand,
which tsdown inlines as a fresh `unique symbol` into each consumer's .d.mts,
breaking nominal identity across module boundaries. The workaround was to
declare @prisma-next/contract-authoring as a direct dep of postgres and mongo
extension packs.
Replace the Symbol with a string-literal phantom key, mirroring the precedent
in codec.ts (`__codecTraits`) and mongo-query-ast/filter-expressions.ts
(`__prismaNextMongoFilter__`). String equality survives .d.mts de-duplication,
so the workaround direct deps are no longer needed — both extension packages
revert to consuming contract-authoring transitively through their family
contract-ts packages.
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The interpreter test imports `mongoFamilyEntityTypes` / `mongoFamilyPslBlockDescriptors` from @prisma-next/family-mongo (layer 9), but the test lived in mongo-contract-psl (layer 2). family-mongo already depends on mongo-contract-psl for runtime, so the test-only devDep on family-mongo created a test-only layer inversion that contradicted what lint:deps enforces for runtime imports. Move the test to test/integration/test/mongo/ where cross-layer imports are legitimate. The test now imports interpretPslDocumentToMongoContract from the @prisma-next/mongo-contract-psl package (rather than from a relative src path) since it's outside the package's source tree. Drop the family-mongo devDep from mongo-contract-psl/package.json. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Refactor D8's output-only precomputed field-type map into a single
channel-parameterized family, mirroring SQL's FieldChannelTypes:
- BuilderBaseChannelType / BuilderFieldChannelType take a Channel param
('output' | 'input'). Enum fields resolve to the value union on both
channels; scalar fields resolve to the codec's per-channel type.
- FieldChannelTypesFromDefinition instantiated twice (output + input);
MongoContractResult now carries both fieldOutputTypes and fieldInputTypes
in its MongoTypeMaps.
- The nullable+many precedence fix (Base[] | null, not (Base|null)[]) is
inherited by the shared family, so it holds on the input channel too.
Thread the enum handle through FieldBuilder as a 4th type parameter so
BuilderEnumValueUnion can detect it from the builder's type. Previously the
handle lived only on an optional __enumHandle property that field.namedType's
return type erased, so the precomputed map silently resolved enum fields to
never. createFieldBuilder is now generic in the handle.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…3 cast (R5/F13)
With FieldInputTypes now on MongoContractResult (A08), the ORM CreateInput
resolves enum fields to the value union instead of never. Prove R5 and remove
the F13 permissive cast:
- mongo.types.test-d.ts: positive matrix (scalar / nullable / many /
nullable+many) plus a non-vacuous negative — create({ role: 'nope' }) is a
compile error and 'nope' is not assignable to the input field type. Verified
non-vacuous: widening the value union back to string makes tsc flag the
@ts-expect-error as unused.
- mongo.enum.e2e.test.ts: delete the AccountsCollection permissive cast (F13);
db.orm.accounts.create(...) typechecks against the real narrowed input.
Out-of-set/null cases keep their MMS runtime rejection via a local `as never`
on the value only (test files are cast-exempt).
The `where` filter still narrows its per-field type through
ExtractMongoCodecTypes, which is never for a TS-DSL contract, so where({ _id })
resolves _id to never. Narrowing where needs a separate mechanism (route it
through FieldInputTypes too); until then the read predicate is cast narrowly
via a documented byId helper. Noted as a follow-up.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…tension surface Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…3/A-004) Replace bare `as` cast in framework-authoring.ts:939 with `blindCast` to comply with the no-bare-casts rule (review thread PRRT_kwDOQM0QJc6J5TS6). Fix `member()` to use `value === undefined ? name : value` instead of `value ?? name`, preventing a type/runtime mismatch when an explicit `null` is passed (review thread PRRT_kwDOQM0QJc6J5TTf). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…cleanup (A-005/A-006c/A-007a) Tighten the empty-members rejection test to mutate a known-valid contract (spread + override only enum.Role.members), so the assertion isolates the enum-members rule rather than failing on unrelated missing required fields (review thread PRRT_kwDOQM0QJc6J5TTu). Add authoring-time validation in buildContractFromDefinition: throw when a model field references an enum via namedType() that is not declared in the contract's enums map (review thread via PRR_kwDOQM0QJc8AAAABDLQDCQ). Remove the redundant decorative section-banner comment in contract-types.test-d.ts (review body PRR_kwDOQM0QJc8AAAABDJwahw nitpick). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The dangling-enum reference guard cast the loop variable to AnyFieldBuilder, introducing a bare `as` in production code. modelBuilder.__fields is already typed Record<string, FieldBuilder>, so __enumHandle is accessible directly — the cast was unnecessary and is dropped (not blindCast'd). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… into the target facades (revert A02 placement) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Adds a UserRole PSL enum (admin/author/reader, mongo/string@1 codec) to the demo's contract, re-emits contract.json and contract.d.ts, and consumes the enum through the full product path: - Typed write in seed.ts: role field required on every user create - db.enums accessor exposed in db.ts and used via getRoles() in server.ts - /api/roles endpoint returns db.enums.UserRole.values - UserList.tsx renders user.role (typed read through emitted FieldOutputTypes) - App.tsx footer lists the enum + $jsonSchema enforcement as a demo feature - Migration 20260626_add-user-role-enum updates the users collection $jsonSchema validator to enforce the enum constraint via collMod/setValidation - All test creates updated with the now-required role field Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Will Madden <madden@prisma.io> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…m the precomputed map (review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…tract snapshot (not an inlined literal) Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… hand-authored) Replace the hand-authored 20260626_add-user-role-enum migration with genuine prisma-next migration plan output. The planner diffs from the prior migration end-contract (2827cbad) to the current contract (250af57) and emits a collMod on users to add the role enum validator. Also delete the 20260415_add-posts-author-index self-edge migration (from === to with no data ops), which was a pre-existing integrity violation that migration plan correctly rejects. The collMod migration takes its place as the second step in the chain. Update manual-migration.test.ts to cover the planner-generated collMod migration instead of the deleted index migration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…t + value objects, not unknown (regression fix) Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ed field maps; delete the production field-resolver fallback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…the index migration via the planner Add @@index([authorId]) and @@index([createdAt(sort: Desc), authorId]) to the Post model in examples/mongo-demo/src/contract.prisma, re-emit the contract, then run migration plan --from sha256:250af57b (the enum migration end-hash) to generate a planner-produced createIndex migration (20260626T1916_add_posts_indexes). The new migration has from != to and completes the chain: initial → enum → indexes. The two indexes were previously applied by the hand-authored add-posts-author-index migration (deleted in commit 6fb1559 because its from == to was an integrity violation). They are now contract-backed and schema-driven. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…es + regenerate value-objects d.ts MongoTypeMaps<TCodecTypes, TFieldOutputTypes, TFieldInputTypes> now requires all three type arguments. Omitting the field maps is a compile error, so the silent-fallback-to-unknown regression class cannot recur. Exported AnyMongoTypeMaps as the widened constraint for call sites that accept any concrete contract (production generic bounds in query-builder, orm, mongo-orm, mongo extension runtime). Updated every fixture that used 1- or 2-arg MongoTypeMaps: - 6 test fixtures in mongo-contract, mongo-runtime, mongo-orm, integration tests - 1 generated fixture (value-objects/fixtures/generated/mongo-contract.d.ts) — added FieldInputTypes to match what the emitter produces for a scalar-only model - contract-types.test-d.ts — dropped the "defaults to Record<...>" tests (the defaults are removed) and completed 2-arg forms with FieldInputTypes fixtures:check: zero diff (mongo-contract.d.ts glob not covered — see note below) typecheck: 143/143 (0 cached) lint:casts: delta=-1 Note: test/integration/test/value-objects/fixtures/generated/mongo-contract.d.ts is NOT covered by the fixtures:check glob (**/contract.* etc.). There is no mongo emit pipeline for this fixture (the prisma-next.config.ts in that directory is SQL/Postgres-only). The file was hand-maintained before and remains hand-maintained after; it now carries the correct 3-arg form. Adding it to fixtures:check would require a new mongo emit config for the value-objects fixture — flagged for follow-up. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…> codecIdByEnumName - Remove the 3-line "Dual-carrier" block from enum-accessor.ts (lines 78-80): it described a contract concern unrelated to the types that followed it. - Rename `enumCodecIds` to `codecIdByEnumName` in the Mongo PSL interpreter (declaration, build site, two call sites) for clarity. - Tighten the adjacent lookup comment to a plain description of what it does. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…c comment on recursion bound Add a doc comment above BuilderFieldChannelType clarifying it runs once at defineContract time (not per query) and that recursion is bounded by VO nesting depth. Extend contract-builder.types.test-d.ts with the full matrix: - scalar (plain/nullable/many/nullable+many) on both output AND input channels - enum (plain/nullable/many/nullable+many) on both channels, including the precedence-trap negative (.not.toEqualTypeOf for (union | null)[] vs (union)[] | null) - value object (plain/nullable/many) on both channels - nested VO on both channels, with explicit .not.toBeUnknown() to pin the recursion in BuilderBaseChannelType (the :660 concern the author raised) No bugs found during the matrix: nested VO resolves correctly on both channels, and precedence modifiers work as expected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…d rename TML-2891 renamed 'mongo-namespace' → 'mongo-database'. Update the three migration end/start-contract.d.ts snapshots in our branch accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… diff Add incidental-diff note to 0.14→0.15 instructions.md covering the mongo-demo enum migration additions and the migration snapshot updates. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The PSL enum interpreter test was moved to test/integration (to avoid a layer-inversion devDep), but integration's default timeout is 100ms. PSL parse + interpret takes longer. Apply timeouts.typeScriptCompilation (8s) to the describe block. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
17df144 to
2d3f06a
Compare
At a glance
Decision
Mongo gets domain enums end-to-end — declare them, have the database reject out-of-set writes, read them as the value union, introspect them at runtime via
db.enums— as a single vertical. An enum is a domain-plane entity (an ordered map from a member name to a member value); it isn't a target-specific feature. This PR wires the Mongo family onto the framework-level machinery the SQL track already proved.The only Mongo-shaped piece is how the restriction is realized. SQL stores a named value-set plus a
CHECKconstraint; Mongo stores nothing — the restriction lives as anenumkeyword inside the collection's$jsonSchemavalidator atvalidationLevel: 'strict'. No storage entity, no migration-ops parallel — the validator the Mongo family already applies just gains a per-fieldenumkeyword. Mongo has no native enum and no prior PSLenum, so there is no cutover and nothing to retire.Refs TML-2884 — the Mongo track (R10) of Enums as a domain concept. With the SQL cutover (TML-2853) already merged, this closes Phase 1: one enum concept on SQL and Mongo.
How it fits together
Author. The TS DSL gains a Mongo-bound
enumType/memberAPI —bindEnumType<MongoCodecTypes>()mirrors the Postgres binding. The Mongo builder accumulates declared enums intodomain.namespaces[__unbound__].enum[Name](codecId + ordered{ name, value }members) and stamps the referencing field'svalueSetref onto the domain field. PSLenumlowers to the same shape via a newmongoFamilyEnumEntityDescriptor(parallel to the SQL family's) and aprocessEnumDeclarationspath in the Mongo PSL interpreter. The Mongo contract schema gainsenum?on the domain namespace andvalueSet?onRawFieldSchema— both required so the built envelope passes arktype validation.Enforce. The Mongo JSON-Schema deriver injects
$jsonSchema.properties.<field>.enum = [...member values]when a field carries an enumvalueSet. WithvalidationLevel: 'strict'(already hardcoded), MongoDB rejects out-of-set writes. Two field-shape corners need care:enuminsideitems, not on the outer schema — MongoDB applies a top-levelenumto the array value, so it would reject every write.nullin the emittedenumarray.bsonTypeandenumare conjunctive in$jsonSchema; a nullable enum withoutnullinenumcouldn't storenulldespitenullable: true.Read. Mongo's
InferFieldBaseTypegains avalueSetbranch that narrows enum-restricted fields to their literal value union on the no-emit (typeof contract) path. The framework emitter's family-agnosticresolveEnumValuescovers the emit path — so consumers of the emittedcontract.d.tssee the union too, not justtypeof-path consumers. TheMongoClientfacade gainsreadonly enums: UnboundEnums<TContract>—buildNamespacedEnums(contract.domain)wrapped in theunboundNamespace()projection that sqlite already uses. Mongo and sqlite each have one namespace (__unbound__), so the projection drops the key and consumers seedb.enums.Roledirectly.Behavior changes & evidence
domain.namespaces[__unbound__].enum[Name]populated; field carries thevalueSetref; literal tuples preserved through the handle. Round-trip + literal-tuple tests in enum-type.authoring.test.ts, interpreter.enum.test.ts, enum-type.test-d.ts.db.enums.Role(no namespace key) and the accessor surface.MongoMemoryReplSet: out-of-set rejected, in-set round-trips,nullinto a nullable enum succeeds, array elements validated (in / empty / out-of-set),db.enums.Status.ordinalOfreturns declaration order (using an enum whose declaration order differs from lexical, to prove the difference).generateContractDtspipeline and asserts the emittedFieldOutputTypescarries the literal union for scalar / nullable / array enum fields, plus that the domain enum block is present in the emitted namespace type (the mechanism the narrowing rides on — non-vacuity).Testing performed
pnpm build(66/66),pnpm typecheck(138/138),pnpm fixtures:checkzero-diff,pnpm lint:castsdelta=0.@prisma-next/mongo89/89,@prisma-next/mongo-contract121/121,@prisma-next/mongo-contract-psl152/152,@prisma-next/family-mongo149/149.Skill update
n/a — no public CLI surface or error-code changes. Authoring expands additively: new
enumTypeimport +field.namedType(handle)in the TS DSL, and a new PSLenumblock keyword on Mongo. The project's user-facing changelog is captured when TML-2853 is published.Follow-ups
MongoContractResultprecomputesFieldOutputTypes(D8) but notFieldInputTypes, so the F07 ORM write boundary in the e2e test still casts theaccountscollection to a permissiveAccountInputshape. R2 F13 flags this cast as the visible cost; R2 A08 names the structural fix (refactor Mongo'sBuilderFieldOutputType/FieldOutputTypesFromDefinitiontoBuilderFieldChannelType<..., Channel>/FieldChannelTypesFromDefinition<Definition, Channel>to match SQL'sFieldChannelTypesfamily, then instantiate twice). Landing A08 simultaneously closes F13 — they are the same gap viewed from the type-builder altitude vs the test-evidence altitude.tagsis non-nullable. The deriver behavior for the corner is verified in unit tests. The type-level corner is now exercised by F11's test incontract-builder.types.test-d.ts.enumTypeshared home.Duplicated betweenLifted tosql-contract-tsandmongo-contract-ts.@prisma-next/contract-authoringin D7 (R1 A01 cleared).unboundNamespaceduplication. The two-line projection helper is duplicated between sqlite and mongo (same architectural premise, two call sites). Lift when a third unbound-namespace target arrives.expect(dts).toContain(...)against the realgenerateContractDtsoutput, matching every other emit test in the codebase. A future hardening pass could write the emitted.d.tsto a temp file and import it forexpectTypeOf— a project-wide convention change.Alternatives considered
enum, so the domain concept lands directly — author, enforce, and read together in one vertical.MongoEnumType, parallel to the deleted Postgres native enum). Rejected: a Mongo collection has no schema object the way a SQL schema has named types. The validator is the schema object the family already manages; anenumkeyword in$jsonSchemais the realization that already fits.enumTypesource between the two families. Rejected for this slice:architecture.config.jsonforbids mongo→sql imports, and the file is small. Lifting to a framework-shared location is the right long-term move; out of scope here.db.enumsfacade. Initially attempted — exposeddb.enums.__unbound__.Role, breaking the spec's specifieddb.enums.Rolesurface. Corrected to mirror sqlite (the other unbound-namespace target) via theUnboundEnumsprojection.generateContractDtstest in the codebase uses substring assertions on the emitter output, and switching one slice to compile-import would diverge from convention without changing what is being verified. Filed as a project-wide hardening follow-up.Checklist
git commit -s) per the DCO.TML-NNNN: <sentence-case title>form.Summary by CodeRabbit
Release Notes
New Features
enumsfacade with enum values,has,nameOf, andordinalOf, along with enum metadata.Tests