TML-2956: migrate Mongo family attributes to declarative specs#973
TML-2956: migrate Mongo family attributes to declarative specs#973SevInf wants to merge 15 commits into
Conversation
…+ 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>
|
Warning Review limit reached
Next review available in: 21 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughChangesThe 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
Mongo attribute interpretation migration
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
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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 📦
|
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (8)
projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/01-mongo-wiring-map.mdis excluded by!projects/**projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/02-mongo-relation.mdis excluded by!projects/**projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/03-mongo-polymorphism.mdis excluded by!projects/**projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/04-kit-str-value-json.mdis excluded by!projects/**projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/05-mongo-index.mdis excluded by!projects/**projects/typed-attribute-parsers/slices/mongo-attributes/dispatches/06-mongo-textindex-cleanup.mdis excluded by!projects/**projects/typed-attribute-parsers/slices/mongo-attributes/plan.mdis excluded by!projects/**projects/typed-attribute-parsers/slices/mongo-attributes/spec.mdis excluded by!projects/**
📒 Files selected for processing (9)
packages/1-framework/2-authoring/psl-parser/src/attribute-spec/combinators/json.tspackages/1-framework/2-authoring/psl-parser/src/attribute-spec/combinators/str.tspackages/1-framework/2-authoring/psl-parser/src/exports/index.tspackages/1-framework/2-authoring/psl-parser/test/attribute-spec-combinators.test.tspackages/2-mongo-family/2-authoring/contract-psl/src/interpreter.tspackages/2-mongo-family/2-authoring/contract-psl/src/mongo-attribute-specs.tspackages/2-mongo-family/2-authoring/contract-psl/src/psl-helpers.tspackages/2-mongo-family/2-authoring/contract-psl/test/interpreter.polymorphism.test.tspackages/2-mongo-family/2-authoring/contract-psl/test/interpreter.test.ts
| 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); | ||
| } |
There was a problem hiding this comment.
🎯 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}')
PYRepository: 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.tsRepository: 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>
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-
@defaultattributes) 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
AttributeSpecand lowered throughinterpretAttribute. The interesting one is the@@indexfield element —email,email(sort: Desc), andwildcard(tags)are all composed from existing combinators, built per model from its field names (the same dynamic-composition pattern@defaultuses over its function registry):Previously the Mongo interpreter parsed every attribute imperatively off a resolved
ResolvedAttributeview viapsl-helpers.tsstring scanners (parseIndexFieldList,parseRelationAttribute,parseCollation,getNamedArgument, …). All of that is gone.Decision
This PR makes the Mongo family fully spec-driven, mirroring the SQL family:
InterpretCtxwiring — a newmongo-attribute-specs.tsprovides the family-agnosticinterpretModelAttribute/interpretFieldAttributewrappers + ctx builders (a copy of the SQL shape, not a cross-family import).@map/@@map,@relation,@@discriminator/@@base,@@index/@@unique, and@@textIndexnow parse their arguments through specs.str(value)(pinned string literal, for the indextypeset) andjson()(the ADR's one text-encoded exception, forfilter/weights).sortedFieldRef/wildcardPathdissolve intofuncCallcomposition over the model's fields (ADR 231 principle 4, "compose don't special-case").How it fits together
@map/@@map).mongo-attribute-specs.tslands the ctx wiring, proven by migrating the simplest attribute — the mapped field/collection name — end-to-end.@relation(name alias +fields/referencesviafieldRef), then@@discriminator/@@base(field / model-name + value), each replacing a string scanner while leaving the cross-model semantics (backrelation matching, polymorphism consistency) untouched.str(value)andjson()are added topsl-parser— the only new combinators the whole slice needs.@@index/@@uniquethen@@textIndexmigrate 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.Behavior changes & evidence
mongo-attribute-specs.ts(the specs + wiring) andinterpreter.ts(the migrated call sites); byte-identical contract output proven byinterpreter.test.ts+fixtures:check.PSL_INVALID_ATTRIBUTE_SYNTAX(rejected at parse byfieldRef, consistent with SQL@relation); a field that exists but isn't indexable (a relation field) → the semanticPSL_INDEX_FIELD_NOT_FOUND(downstream). Evidence ininterpreter.test.ts+interpreter.polymorphism.test.ts.str(value)pins a string literal;json()reads an opaque JSON object from a quoted string. Seestr.ts+json.ts; evidence inattribute-spec-combinators.test.ts.psl-helpers.tsshrinks from a bag of string scanners to a handful of survivors (getAttribute,lowerFirst,parseProjectionList,parseQuotedStringLiteral).Reviewer notes
sortedFieldRef/wildcardPathwere considered and dropped:field(sort: Desc)isfuncCall(field, { named: { sort } })andwildcard(scope)isfuncCall('wildcard', …), so the element isoneOfoverfieldRef+ the per-fieldfuncCallarms — pure composition, built dynamically per model.type, a non-boolsparse, invalidfilter/weightsJSON, a badsort) becomePSL_INVALID_ATTRIBUTE_SYNTAX;@@textIndexnow rejects args it doesn't accept (type/sparse/expireAfterSeconds) where the old path silently ignored them. AllPSL_INVALID_INDEXshape rules, the one-@@textIndex-per-collection guard, andPSL_INDEX_FIELD_NOT_FOUND(for relation fields) are preserved.oneOf, an absent-field reference surfaces as a genericExpected one of: …rather than naming the field — the same trade-off the SQL slices accepted. A futureoneOf-diagnostic enhancement could restore field-naming; out of scope here.@@indexon one model.findModelAttributeNodereturns 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.interpreter.ts(collectIndexes) — the index-shape validation andMongoIndexconstruction are byte-for-byte unchanged; only the argument source moved from string parsers to the spec output.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 testspnpm --filter @prisma-next/psl-parser build && typecheck && test— clean; 635 testspnpm --filter @prisma-next/sql-contract-psl test— 346 (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/836parseIndexFieldList/parseRelationAttribute/parseCollation/getNamedArgument/…) — zero remaining incontract-psl/srcAlternatives considered
sortedFieldRef/wildcardPathcombinators. Rejected: with the model in context the field names are known, sooneOf(fieldRef, ...fields.map(funcCall), funcCall('wildcard'))composes the same grammar without new kit surface — the same reason@defaultdroppedfuncCallFrom.filter/weightsquoted JSON → object literals;include/excludequoted bracket-strings → native lists). Rejected: it would break existing Mongo schemas.json()preserves the quoted-JSON surface;include/excludestaystr()+parseProjectionList.PSL_INDEX_FIELD_NOT_FOUNDfor all field misses. Rejected:fieldRefvalidates existence at parse time, and the natural split (missing → syntax, relation-field-not-indexable → semantic) is both cleaner and consistent with how@relationalready behaves.Checklist
git commit -s) per the DCO.TML-NNNN: <sentence-case title>form.Summary by CodeRabbit
New Features
Bug Fixes