Skip to content

TML-2956: migrate Mongo family attributes to declarative specs#973

Open
SevInf wants to merge 15 commits into
mainfrom
tml-2956-mongo-attributes
Open

TML-2956: migrate Mongo family attributes to declarative specs#973
SevInf wants to merge 15 commits into
mainfrom
tml-2956-mongo-attributes

Conversation

@SevInf

@SevInf SevInf commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Linked issue

Refs TML-2956 — "Language Tools Support Prisma Next PSL" (the typed-attribute-parsers project's umbrella ticket).

Completes the family migrations begun in #932 (SQL non-@default attributes) and #938 (SQL @default): this PR brings the Mongo family onto the same declarative attribute-spec kit. After it, every attribute in both families validates its arguments through the kit — no hand-written string parsers remain.

At a glance

Every Mongo attribute is now described by an AttributeSpec and lowered through interpretAttribute. The interesting one is the @@index field element — email, email(sort: Desc), and wildcard(tags) are all composed from existing combinators, built per model from its field names (the same dynamic-composition pattern @default uses over its function registry):

const sortSig = { named: { sort: oneOf(identifier('Asc'), identifier('Desc')) } } satisfies FuncCallSig;

function indexFieldElement(fieldNames: readonly string[]): ArgType<string | TypedFuncCall> {
  return oneOf(
    fieldRef('self'),                                                                            // email          → "email"
    funcCall('wildcard', { positional: [{ key: 'scope', type: optional(fieldRef('self')) }] }),  // wildcard(tags)  → { fn: 'wildcard', … }
    ...fieldNames.map((name) => funcCall(name, sortSig)),                                          // email(sort: Desc) → { fn: 'email', args: { sort } }
  );
}

Previously the Mongo interpreter parsed every attribute imperatively off a resolved ResolvedAttribute view via psl-helpers.ts string scanners (parseIndexFieldList, parseRelationAttribute, parseCollation, getNamedArgument, …). All of that is gone.

Decision

This PR makes the Mongo family fully spec-driven, mirroring the SQL family:

  1. Mongo InterpretCtx wiring — a new mongo-attribute-specs.ts provides the family-agnostic interpretModelAttribute/interpretFieldAttribute wrappers + ctx builders (a copy of the SQL shape, not a cross-family import).
  2. Every Mongo attribute migrated@map/@@map, @relation, @@discriminator/@@base, @@index/@@unique, and @@textIndex now parse their arguments through specs.
  3. Two new kit combinatorsstr(value) (pinned string literal, for the index type set) and json() (the ADR's one text-encoded exception, for filter/weights).
  4. No bespoke index-element combinators — the sketched sortedFieldRef/wildcardPath dissolve into funcCall composition over the model's fields (ADR 231 principle 4, "compose don't special-case").
  5. Legacy parsers deleted — every Mongo attribute-argument string parser is removed behind a grep gate; the interpreter keeps only the genuinely-semantic logic.

How it fits together

  1. Wiring first (@map/@@map). mongo-attribute-specs.ts lands the ctx wiring, proven by migrating the simplest attribute — the mapped field/collection name — end-to-end.
  2. The simple attributes. @relation (name alias + fields/references via fieldRef), then @@discriminator/@@base (field / model-name + value), each replacing a string scanner while leaving the cross-model semantics (backrelation matching, polymorphism consistency) untouched.
  3. The kit leaves. str(value) and json() are added to psl-parser — the only new combinators the whole slice needs.
  4. The index grammar. @@index/@@unique then @@textIndex migrate to per-model specs (the dynamic field element + the full named-arg surface — type, sparse, expireAfterSeconds, filter, include/exclude, weights, language, and the 9 collation args). The dense index-shape validation stays in the interpreter, reading normalized values.
  5. Cleanup. With all three index attributes spec-driven, the orphaned parsers are deleted; a grep gate proves none remain.

Behavior changes & evidence

  • Every Mongo attribute is spec-validated. See mongo-attribute-specs.ts (the specs + wiring) and interpreter.ts (the migrated call sites); byte-identical contract output proven by interpreter.test.ts + fixtures:check.
  • Field-existence errors split coherently (operator "Option A"). A field that doesn't exist on the model → PSL_INVALID_ATTRIBUTE_SYNTAX (rejected at parse by fieldRef, consistent with SQL @relation); a field that exists but isn't indexable (a relation field) → the semantic PSL_INDEX_FIELD_NOT_FOUND (downstream). Evidence in interpreter.test.ts + interpreter.polymorphism.test.ts.
  • Two new kit combinators. str(value) pins a string literal; json() reads an opaque JSON object from a quoted string. See str.ts + json.ts; evidence in attribute-spec-combinators.test.ts.
  • Legacy parsers gone. psl-helpers.ts shrinks from a bag of string scanners to a handful of survivors (getAttribute, lowerFirst, parseProjectionList, parseQuotedStringLiteral).

Reviewer notes

  • No bespoke index-element combinators. sortedFieldRef/wildcardPath were considered and dropped: field(sort: Desc) is funcCall(field, { named: { sort } }) and wildcard(scope) is funcCall('wildcard', …), so the element is oneOf over fieldRef + the per-field funcCall arms — pure composition, built dynamically per model.
  • Diagnostic-code shifts are intentional (Option A, consistent with TML-2956: migrate 7 SQL attributes to declarative attribute specs #932/TML-2956: migrate @default to declarative attribute specs (both paths) #938). Malformed/unknown index arguments (an unknown type, a non-bool sparse, invalid filter/weights JSON, a bad sort) become PSL_INVALID_ATTRIBUTE_SYNTAX; @@textIndex now rejects args it doesn't accept (type/sparse/expireAfterSeconds) where the old path silently ignored them. All PSL_INVALID_INDEX shape rules, the one-@@textIndex-per-collection guard, and PSL_INDEX_FIELD_NOT_FOUND (for relation fields) are preserved.
  • Coarse-diagnostic trade-off (accepted, ADR 231). Because the index element is oneOf, an absent-field reference surfaces as a generic Expected one of: … rather than naming the field — the same trade-off the SQL slices accepted. A future oneOf-diagnostic enhancement could restore field-naming; out of scope here.
  • Multiple @@index on one model. findModelAttributeNode returns the first same-named node, so the loop maps each resolved attribute to its AST node by position (node.attributes() order is 1:1 with the resolved list) — guarded by a new multi-index test.
  • Largest diff: interpreter.ts (collectIndexes) — the index-shape validation and MongoIndex construction are byte-for-byte unchanged; only the argument source moved from string parsers to the spec output.
  • Project artefacts under projects/typed-attribute-parsers/slices/mongo-attributes/ are included for review provenance (path-filtered out of automated review); they are migrated/removed at project close-out.

Verification

Run on final HEAD:

  • pnpm --filter @prisma-next/mongo-contract-psl build && typecheck && test — clean; 155 tests
  • pnpm --filter @prisma-next/psl-parser build && typecheck && test — clean; 635 tests
  • pnpm --filter @prisma-next/sql-contract-psl test346 (unaffected by the additive kit changes)
  • pnpm build — 68/68 · pnpm fixtures:check — clean, no contract drift · pnpm lint:deps — 0 · pnpm lint:framework-vocabulary — 836/836
  • Grep gate: the legacy Mongo attribute parsers (parseIndexFieldList/parseRelationAttribute/parseCollation/getNamedArgument/…) — zero remaining in contract-psl/src

Alternatives considered

  • Bespoke sortedFieldRef/wildcardPath combinators. Rejected: with the model in context the field names are known, so oneOf(fieldRef, ...fields.map(funcCall), funcCall('wildcard')) composes the same grammar without new kit surface — the same reason @default dropped funcCallFrom.
  • Changing the text-encoded index surface (filter/weights quoted JSON → object literals; include/exclude quoted bracket-strings → native lists). Rejected: it would break existing Mongo schemas. json() preserves the quoted-JSON surface; include/exclude stay str() + parseProjectionList.
  • Preserving PSL_INDEX_FIELD_NOT_FOUND for all field misses. Rejected: fieldRef validates existence at parse time, and the natural split (missing → syntax, relation-field-not-indexable → semantic) is both cleaner and consistent with how @relation already behaves.

Checklist

  • All commits are signed off (git commit -s) per the DCO.
  • I read CONTRIBUTING.md and the change is scoped to one logical concern (the Mongo family attribute migration).
  • Tests are updated.
  • The PR title is in TML-NNNN: <sentence-case title> form.

Summary by CodeRabbit

  • New Features

    • Added JSON object parsing for attribute arguments.
    • Added support for matching string attributes against a specific expected value.
    • Improved MongoDB PSL attribute handling for mappings, relations, polymorphism, and indexes.
  • Bug Fixes

    • Improved validation and source locations for invalid attributes and index definitions.
    • Correctly preserves multiple index declarations on the same model.

SevInf added 14 commits July 14, 2026 11:03
…+ dispatch plan)

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…@map/@@Map)

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…attribute kit

Land the Mongo-side wiring for the declarative attribute-spec kit by adding
mongo-attribute-specs.ts (mirroring the SQL family, family-agnostic, no
cross-family import) and migrating @map/@@Map end-to-end through
interpretAttribute.

- resolveFieldMappings/resolveCollectionName now take { model, sourceFile,
  sourceId, diagnostics } and interpret the map spec, draining failures into
  diagnostics.
- Thread sourceFile/sourceId/diagnostics into all call sites, including
  collectPolymorphismDeclarations and resolvePolymorphism.
- Variant presence check uses getAttribute instead of getMapName.
- Delete the now-dead getMapName helper (getAttribute/stripQuotes retained).

Behaviour is byte-identical for @map/@@Map; existing suite + fixtures:check
are the primary signal.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
@unique presence-only)

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
… spec)

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Replace the hand-written parseRelationAttribute string extraction with a
declarative relationFieldSpec (name/fields/references, no refine) interpreted
through interpretFieldAttribute, mirroring the SQL family. fieldRef adds
field-existence validation the old parser lacked: a @relation naming a
non-existent field now emits PSL_INVALID_ATTRIBUTE_SYNTAX. Valid schemas lower
byte-identically. Retire parseRelationAttribute/ParsedRelationAttribute and the
now-dead stripQuotes helper; keep parseFieldList.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
@base to specs)

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
… specs

Replace the imperative getPositionalArgument/parseQuotedStringLiteral
parsing in collectPolymorphismDeclarations with findModelAttributeNode +
interpretModelAttribute against new discriminatorModelSpec/baseModelSpec,
copied from the SQL templates. Argument-shape errors (missing arg,
non-quoted value, non-existent discriminator field) now surface as
grammar PSL_INVALID_ATTRIBUTE_SYNTAX; the discriminator-field-must-be-
String check stays a semantic PSL_INVALID_ATTRIBUTE_ARGUMENT.

resolvePolymorphism semantics are unchanged. getPositionalArgument and
parseQuotedStringLiteral remain defined in psl-helpers for the index
attributes.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…mongo index surface)

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Add two leaf combinators to the attribute-spec kit for the Mongo index
argument surface (wired in a later dispatch):

- str(value): a pinned string-literal overload of str(), mirroring
  num()/num(value). Pins to a single literal (e.g. str("hashed")) for
  digit-leading index type tokens that cannot be bare identifiers.
- json(): reads an opaque JSON object from a quoted, parser-decoded JSON
  string, matching the interpreter parseJsonArg behaviour (non-array
  object only). The single JSON.parse-of-unknown narrowing is a justified
  blindCast; no bare as.

Both additions are additive: the unpinned str() and all existing
psl-parser/sql/mongo tests stay green with no edits. Adds focused unit
tests for both combinators.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
… to specs)

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…o attribute specs

Route model-level @@index and @@unique argument parsing through
interpretModelAttribute + a new buildIndexModelSpec, replacing the imperative
getNamedArgument/parse* helpers. The dense index-shape validation
(PSL_INVALID_INDEX in all forms, the collation-locale-required rule), the
PSL_INDEX_FIELD_NOT_FOUND existence check, key-building, and MongoIndex
construction are unchanged; only the argument source moves onto specs. Lowering
is byte-identical for valid schemas.

buildIndexModelSpec composes a per-model field element
(oneOf(fieldRef, wildcard(scope?), field(sort:))) plus the full named-arg
surface (type/sparse/expireAfterSeconds/filter[json]/include/exclude[str]/
default_language/languageOverride + 9 collation args). @@textIndex stays on its
existing pre-spec branch (migrated in a later dispatch).

Per operator Option A, argument-shape errors now surface as
PSL_INVALID_ATTRIBUTE_SYNTAX: a field reference absent from the model is
rejected at the grammar layer by fieldRef, so PSL_INDEX_FIELD_NOT_FOUND now
guards only present-but-not-indexable (relation) fields. parseIndexDirection is
removed (its sole caller moved to the spec path; @@textIndex never used it).

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
…delete legacy parsers)

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Add buildTextIndexModelSpec and route @@textIndex through the spec
interpreter like @@index/@@unique, filling the same normalized locals via
a cast-free two-branch (isTextIndex) structure since the two specs infer
different named-arg shapes. Weights are number-filtered via a new
extractWeights helper (typeof-narrowed, no cast).

This orphans the pre-spec argument parsers, so delete them (biome
noUnusedVariables): parseCollation, parseNumericArg, parseBooleanArg,
parseJsonArg, stripQuotesHelper (interpreter.ts) and parseIndexFieldList,
parseIndexFieldSegment, parseFieldList, splitTopLevel, getNamedArgument,
getPositionalArgument (psl-helpers.ts). Keep parseProjectionList,
getAttribute, lowerFirst, parseQuotedStringLiteral, ParsedIndexField.

Reword the comments naming the removed parseIndexDirection/parseCollation.
Per Option A, @@textIndex now rejects undeclared args and shifts
undeclared-field references to PSL_INVALID_ATTRIBUTE_SYNTAX (via fieldRef);
update the one shifted assertion. Contracts stay byte-identical for valid
schemas.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
@SevInf
SevInf requested a review from a team as a code owner July 14, 2026 15:30
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@SevInf, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 21 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 1c0675a4-92c7-4124-b744-4e0972c30bfb

📥 Commits

Reviewing files that changed from the base of the PR and between 7235a88 and e78cc55.

📒 Files selected for processing (1)
  • packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts
📝 Walkthrough

Walkthrough

Changes

The PSL parser adds JSON object parsing and pinned string literals. Mongo contract interpretation now uses typed attribute specifications for mappings, relations, polymorphism, and indexes, with source-aware diagnostics. Legacy parsing helpers are removed and affected diagnostic and index tests are updated.

PSL attribute combinators

Layer / File(s) Summary
Parser combinators and coverage
packages/1-framework/2-authoring/psl-parser/src/attribute-spec/combinators/*, packages/1-framework/2-authoring/psl-parser/src/exports/index.ts, packages/1-framework/2-authoring/psl-parser/test/attribute-spec-combinators.test.ts
Adds json(), supports pinned values in str(value), re-exports json, and tests accepted and rejected literal forms.

Mongo attribute interpretation migration

Layer / File(s) Summary
Mongo attribute specifications
packages/2-mongo-family/2-authoring/contract-psl/src/mongo-attribute-specs.ts, packages/2-mongo-family/2-authoring/contract-psl/src/psl-helpers.ts
Adds typed Mongo attribute lookup, interpretation, relation, mapping, polymorphism, and index specifications while removing superseded parsing helpers.
Attribute and polymorphism interpretation
packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts, packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.polymorphism.test.ts, packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.test.ts
Rewires mappings, relations, discriminator/base declarations, and variant collection handling through attribute specs and updates related diagnostic expectations.
Typed index interpretation
packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts, packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.test.ts
Interprets index attributes with generated specs, normalizes fields and options, and verifies multiple indexes and grammar-layer validation errors.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PSL_AST
  participant mongo_attribute_specs
  participant Mongo_interpreter
  participant Diagnostics
  Mongo_interpreter->>PSL_AST: locate model and field attribute nodes
  Mongo_interpreter->>mongo_attribute_specs: interpretModelAttribute or interpretFieldAttribute
  mongo_attribute_specs->>Diagnostics: append source-spanned parse failures
  mongo_attribute_specs-->>Mongo_interpreter: typed attribute value or undefined
Loading

Possibly related PRs

  • prisma/prisma-next#851: Related Mongo interpreter migration from legacy PSL parsing to structured attribute inputs.
  • prisma/prisma-next#891: Related PSL attribute-spec combinator changes, including pinned string parsing.

Suggested reviewers: wmadden, wmadden-electric

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: migrating Mongo family attributes to declarative specs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2956-mongo-attributes

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

@prisma-next/extension-author-tools

npm i https://pkg.pr.new/@prisma-next/extension-author-tools@973

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/@prisma-next/mongo-runtime@973

@prisma-next/family-mongo

npm i https://pkg.pr.new/@prisma-next/family-mongo@973

@prisma-next/sql-runtime

npm i https://pkg.pr.new/@prisma-next/sql-runtime@973

@prisma-next/family-sql

npm i https://pkg.pr.new/@prisma-next/family-sql@973

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/@prisma-next/extension-arktype-json@973

@prisma-next/middleware-cache

npm i https://pkg.pr.new/@prisma-next/middleware-cache@973

@prisma-next/mongo

npm i https://pkg.pr.new/@prisma-next/mongo@973

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/@prisma-next/extension-paradedb@973

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/@prisma-next/extension-pgvector@973

@prisma-next/extension-postgis

npm i https://pkg.pr.new/@prisma-next/extension-postgis@973

@prisma-next/postgres

npm i https://pkg.pr.new/@prisma-next/postgres@973

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/@prisma-next/sql-orm-client@973

@prisma-next/sqlite

npm i https://pkg.pr.new/@prisma-next/sqlite@973

@prisma-next/extension-supabase

npm i https://pkg.pr.new/@prisma-next/extension-supabase@973

@prisma-next/target-mongo

npm i https://pkg.pr.new/@prisma-next/target-mongo@973

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/@prisma-next/adapter-mongo@973

@prisma-next/driver-mongo

npm i https://pkg.pr.new/@prisma-next/driver-mongo@973

@prisma-next/contract

npm i https://pkg.pr.new/@prisma-next/contract@973

@prisma-next/utils

npm i https://pkg.pr.new/@prisma-next/utils@973

@prisma-next/config

npm i https://pkg.pr.new/@prisma-next/config@973

@prisma-next/errors

npm i https://pkg.pr.new/@prisma-next/errors@973

@prisma-next/framework-components

npm i https://pkg.pr.new/@prisma-next/framework-components@973

@prisma-next/operations

npm i https://pkg.pr.new/@prisma-next/operations@973

@prisma-next/ts-render

npm i https://pkg.pr.new/@prisma-next/ts-render@973

@prisma-next/contract-authoring

npm i https://pkg.pr.new/@prisma-next/contract-authoring@973

@prisma-next/ids

npm i https://pkg.pr.new/@prisma-next/ids@973

@prisma-next/psl-parser

npm i https://pkg.pr.new/@prisma-next/psl-parser@973

@prisma-next/psl-printer

npm i https://pkg.pr.new/@prisma-next/psl-printer@973

@prisma-next/cli

npm i https://pkg.pr.new/@prisma-next/cli@973

@prisma-next/cli-telemetry

npm i https://pkg.pr.new/@prisma-next/cli-telemetry@973

@prisma-next/config-loader

npm i https://pkg.pr.new/@prisma-next/config-loader@973

@prisma-next/emitter

npm i https://pkg.pr.new/@prisma-next/emitter@973

@prisma-next/language-server

npm i https://pkg.pr.new/@prisma-next/language-server@973

@prisma-next/migration-tools

npm i https://pkg.pr.new/@prisma-next/migration-tools@973

prisma-next

npm i https://pkg.pr.new/prisma-next@973

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/@prisma-next/vite-plugin-contract-emit@973

@prisma-next/mongo-codec

npm i https://pkg.pr.new/@prisma-next/mongo-codec@973

@prisma-next/mongo-contract

npm i https://pkg.pr.new/@prisma-next/mongo-contract@973

@prisma-next/mongo-value

npm i https://pkg.pr.new/@prisma-next/mongo-value@973

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/@prisma-next/mongo-contract-psl@973

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/@prisma-next/mongo-contract-ts@973

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/@prisma-next/mongo-emitter@973

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/@prisma-next/mongo-schema-ir@973

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/@prisma-next/mongo-query-ast@973

@prisma-next/mongo-orm

npm i https://pkg.pr.new/@prisma-next/mongo-orm@973

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/@prisma-next/mongo-query-builder@973

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/@prisma-next/mongo-lowering@973

@prisma-next/mongo-wire

npm i https://pkg.pr.new/@prisma-next/mongo-wire@973

@prisma-next/sql-contract

npm i https://pkg.pr.new/@prisma-next/sql-contract@973

@prisma-next/sql-errors

npm i https://pkg.pr.new/@prisma-next/sql-errors@973

@prisma-next/sql-operations

npm i https://pkg.pr.new/@prisma-next/sql-operations@973

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/@prisma-next/sql-schema-ir@973

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/@prisma-next/sql-contract-psl@973

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/@prisma-next/sql-contract-ts@973

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/@prisma-next/sql-contract-emitter@973

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/@prisma-next/sql-lane-query-builder@973

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/@prisma-next/sql-relational-core@973

@prisma-next/sql-builder

npm i https://pkg.pr.new/@prisma-next/sql-builder@973

@prisma-next/target-postgres

npm i https://pkg.pr.new/@prisma-next/target-postgres@973

@prisma-next/target-sqlite

npm i https://pkg.pr.new/@prisma-next/target-sqlite@973

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/@prisma-next/adapter-postgres@973

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/@prisma-next/adapter-sqlite@973

@prisma-next/driver-postgres

npm i https://pkg.pr.new/@prisma-next/driver-postgres@973

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/@prisma-next/driver-sqlite@973

commit: e78cc55

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
postgres / no-emit 155.93 KB (0%)
postgres / emit 130.97 KB (0%)
mongo / no-emit 98.71 KB (0%)
mongo / emit 89.43 KB (0%)
cf-worker / no-emit 182.94 KB (0%)
cf-worker / emit 155.41 KB (0%)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts`:
- Around line 136-182: Memoize the results of resolveFieldMappings and
resolveCollectionName per model so repeated calls reuse the previously
interpreted `@map/`@@map values and do not append duplicate diagnostics. Add or
use a model-keyed cache in the surrounding interpreter state, ensuring malformed
attributes are interpreted once while preserving the existing fallback names and
mappings.
🪄 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: bde6c1ba-db12-46a9-a045-1cd5f607dd27

📥 Commits

Reviewing files that changed from the base of the PR and between a7344a3 and 7235a88.

⛔ Files ignored due to path filters (8)
  • projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/01-mongo-wiring-map.md is excluded by !projects/**
  • projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/02-mongo-relation.md is excluded by !projects/**
  • projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/03-mongo-polymorphism.md is excluded by !projects/**
  • projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/04-kit-str-value-json.md is excluded by !projects/**
  • projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/05-mongo-index.md is excluded by !projects/**
  • projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/06-mongo-textindex-cleanup.md is excluded by !projects/**
  • projects/typed-attribute-parsers/slices/mongo-attributes/plan.md is excluded by !projects/**
  • projects/typed-attribute-parsers/slices/mongo-attributes/spec.md is excluded by !projects/**
📒 Files selected for processing (9)
  • packages/1-framework/2-authoring/psl-parser/src/attribute-spec/combinators/json.ts
  • packages/1-framework/2-authoring/psl-parser/src/attribute-spec/combinators/str.ts
  • packages/1-framework/2-authoring/psl-parser/src/exports/index.ts
  • packages/1-framework/2-authoring/psl-parser/test/attribute-spec-combinators.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts
  • packages/2-mongo-family/2-authoring/contract-psl/src/mongo-attribute-specs.ts
  • packages/2-mongo-family/2-authoring/contract-psl/src/psl-helpers.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.polymorphism.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.test.ts

Comment on lines +136 to 182
function resolveFieldMappings(input: {
readonly model: ModelSymbol;
readonly sourceFile: SourceFile;
readonly sourceId: string;
readonly diagnostics: ContractSourceDiagnostic[];
}): FieldMappings {
const { model, sourceFile, sourceId, diagnostics } = input;
const pslNameToMapped = new Map<string, string>();
for (const field of Object.values(model.fields)) {
const mapped = getMapName(field.attributes) ?? field.name;
const mapNode = findFieldAttributeNode(field, 'map');
const mapped =
(mapNode
? interpretFieldAttribute({
node: mapNode,
spec: mapFieldSpec,
model,
field,
sourceFile,
sourceId,
diagnostics,
})?.name
: undefined) ?? field.name;
pslNameToMapped.set(field.name, mapped);
}
return { pslNameToMapped };
}

function resolveCollectionName(model: ModelSymbol): string {
return getMapName(model.attributes) ?? lowerFirst(model.name);
function resolveCollectionName(input: {
readonly model: ModelSymbol;
readonly sourceFile: SourceFile;
readonly sourceId: string;
readonly diagnostics: ContractSourceDiagnostic[];
}): string {
const { model, sourceFile, sourceId, diagnostics } = input;
const mapNode = findModelAttributeNode(model, 'map');
const name = mapNode
? interpretModelAttribute({
node: mapNode,
spec: mapModelSpec,
model,
sourceFile,
sourceId,
diagnostics,
})?.name
: undefined;
return name ?? lowerFirst(model.name);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and read the relevant region with line numbers.
ast-grep outline packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts --view expanded || true
echo '--- interpreter.ts around resolveFieldMappings/resolveCollectionName ---'
sed -n '120,220p' packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts

echo '--- call sites for resolveFieldMappings/resolveCollectionName ---'
rg -n "resolveFieldMappings|resolveCollectionName" packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts

echo '--- interpretAttribute helpers ---'
rg -n "function interpret(Field|Model)Attribute|interpret(Field|Model)Attribute\\(" packages/2-mongo-family/2-authoring/contract-psl/src -g '!**/*.d.ts'

Repository: prisma/prisma-next

Length of output: 8188


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect parser/diagnostic behavior for repeated attribute interpretation.
rg -n "ContractSourceDiagnostic|diagnostics.push|find(Field|Model)AttributeNode|parseRelationAttribute|parse.*Attribute" packages/2-mongo-family/2-authoring/contract-psl/src -g '!**/*.d.ts'

echo '--- surrounding implementation of interpretFieldAttribute / interpretModelAttribute ---'
sed -n '1,260p' packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts

echo '--- any memoization / caching already present ---'
rg -n "new Map<|cache|memo" packages/2-mongo-family/2-authoring/contract-psl/src -g '!**/*.d.ts'

Repository: prisma/prisma-next

Length of output: 17211


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Probe whether repeated helper calls can emit the same diagnostic twice by tracing call sites.
python3 - <<'PY'
from pathlib import Path
p = Path('packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts')
text = p.read_text()
for needle in [
    'resolveFieldMappings(',
    'resolveCollectionName(',
    'diagnostics.push(',
    'interpretFieldAttribute({',
    'interpretModelAttribute({',
]:
    print(f'## {needle}')
    for i, line in enumerate(text.splitlines(), 1):
        if needle in line:
            print(f'{i}: {line}')
PY

Repository: prisma/prisma-next

Length of output: 1967


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the specific regions around the helper definitions and call sites.
sed -n '1,240p' packages/2-mongo-family/2-authoring/contract-psl/src/interpreter.ts

Repository: prisma/prisma-next

Length of output: 8562


Cache model map lookups to avoid duplicate diagnostics

resolveFieldMappings and resolveCollectionName are called multiple times for the same model, and each call re-parses @map/@@map and appends failures to the shared diagnostics array. On malformed attributes, the same error can surface multiple times. Memoize the per-model result so each attribute is interpreted once.

🤖 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/src/interpreter.ts` around
lines 136 - 182, Memoize the results of resolveFieldMappings and
resolveCollectionName per model so repeated calls reuse the previously
interpreted `@map/`@@map values and do not append duplicate diagnostics. Add or
use a model-keyed cache in the surrounding interpreter state, ensuring malformed
attributes are interpreted once while preserving the existing fallback names and
mappings.

The bare `as Contract['storage']` cast tripped scripts/lint-no-contract-cast.mjs,
failing CI's Lint job. Replace it with blindCast<T, Reason>, an identity
re-type, removing the as-Contract smell and one bare as.

Signed-off-by: Serhii Tatarintsev <tatarintsev@prisma.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant