Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,13 @@ describe('#13222 part (1) — driver-mongodb refuses `reference_to` at the schem

it('does not index a `lookup` that declares no target — `reference` is read for truth, not presence', async () => {
// Measured on `FieldSchema` built from this tree: `{ type: 'lookup' }` with
// no `reference`, and `{ type: 'lookup', reference: '' }`, BOTH parse
// successfully — the spec's prose calls `reference` required for these
// types, but the schema does not enforce it. So this is a shape an author
// can really publish, not a hypothetical, and the arm has to answer for it.
// no `reference`, and `{ type: 'lookup', reference: '' }`, are BOTH REFUSED
// (`custom` on the `reference` path) — #13927 made the "required for these
// types" in the spec's own prose enforced; both parsed successfully until
// then. The shape is still not hypothetical, because it does not arrive
// through Zod: `syncSchema(object, schema: unknown)` casts and forwards
// verbatim, which is the seam this test calls directly, so the arm still
// has to answer for it.
//
// It answers by declining: `idx_FIELD_lookup` exists to serve a join, and a
// lookup with no declared target has no join to serve — the index would
Expand Down
34 changes: 26 additions & 8 deletions packages/drivers/driver-mongodb/src/mongodb-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,14 @@ interface FieldDef {
* ⚠️ Truthiness rather than `!== undefined`, and that difference is load
* bearing rather than inherited. Measured on `FieldSchema` built from this
* tree: `{ type: 'lookup' }` with NO `reference`, and `{ type: 'lookup',
* reference: '' }`, both parse SUCCESSFULLY — the "required for these types"
* in the spec's own prose is not enforced by the schema. So a lookup that
* points nowhere is a shape an author can really publish, and it must not
* get `idx_FIELD_lookup`: an index for a join whose target is undeclared
* costs writes and buys no read. Truthiness declines exactly that shape.
* reference: '' }`, are BOTH REFUSED — `custom` on the `reference` path,
* since #13927 made the "required for these types" in the spec's own prose
* enforced (it parsed successfully until then). The shape still reaches this
* arm regardless, because metadata gets here without meeting Zod at all —
* `syncSchema(object, schema: unknown)` casts and forwards verbatim — and it
* must not get `idx_FIELD_lookup`: an index for a join whose target is
* undeclared costs writes and buys no read. Truthiness declines exactly that
* shape.
*/
reference?: unknown;
multiple?: boolean;
Expand Down Expand Up @@ -110,9 +113,9 @@ interface ObjectDef {
*
* ## Why the DDL seam needs a door the schema already has
*
* `reference` is the only relationship spelling the spec declares;
* `reference_to` is a REJECTED ALIAS, not a normalised one. Measured against
* `@objectstack/spec` built from this tree:
* `reference` is the only relationship spelling the spec declares. ON THE
* AUTHORING FACE `reference_to` is a REJECTED ALIAS, not a normalised one.
* Measured against `@objectstack/spec` built from this tree:
*
* ```
* FieldSchema.safeParse({ name:'company_id', type:'lookup', reference_to:'company' })
Expand All @@ -122,6 +125,21 @@ interface ObjectDef {
* these were dropped silently ..."
* ```
*
* ⚠️ That verdict is the authoring face and only the authoring face — do NOT
* read this door as "a stored `reference_to` stays verbatim forever". #13700
* landed the `field-reference-to-alias` conversion (`toMajor: 18`,
* `retiredFromLoadPath: true`, in `packages/spec/src/conversions/registry.ts`),
* and its docblock already states the split this comment has to be read
* against: the entry "covers the two paths that serve or rewrite EXISTING data
* — stored rehydration and `os migrate meta`", where the key is NORMALISED to
* `reference` rather than refused, while "the DDL doors above keep guarding
* the third path (metadata handed straight to a driver, around both the gate
* and the stored pass); they are downstream of this entry, not replaced by
* it." This door is one of those DDL doors — and the third path is exactly the
* one this driver sits on, since `syncSchema(object, schema: unknown)` casts
* and forwards verbatim with no Zod and no stored pass. Refused when authored,
* rewritten when already at rest, refused again here.
*
* Until this door, the driver read `reference_to` and ONLY `reference_to`, as
* the gate on the field-level join index below. So one key had TWO doors with
* opposite answers: the authoring door refused it, while this one silently
Expand Down
20 changes: 17 additions & 3 deletions packages/drivers/driver-sql/src/sql-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1488,9 +1488,9 @@ function refuseDateBucketedGroupBy(granularity: string, bucketedHere: string[],
*
* ## Why the DDL seam needs a door the schema already has
*
* `reference` is the only relationship spelling the spec declares;
* `reference_to` is a REJECTED ALIAS, not a normalised one. Measured on
* `origin/main`:
* `reference` is the only relationship spelling the spec declares. ON THE
* AUTHORING FACE `reference_to` is a REJECTED ALIAS, not a normalised one.
* Measured on `origin/main`:
*
* ```
* FieldSchema.safeParse({ name:'parent', type:'lookup', reference_to:'p' })
Expand All @@ -1499,6 +1499,20 @@ function refuseDateBucketedGroupBy(granularity: string, bucketedHere: string[],
* Did you mean `reference_to` → `reference`?"
* ```
*
* ⚠️ That verdict is the authoring face and only the authoring face — do NOT
* read this door as "a stored `reference_to` stays verbatim forever". #13700
* landed the `field-reference-to-alias` conversion (`toMajor: 18`,
* `retiredFromLoadPath: true`, in `packages/spec/src/conversions/registry.ts`),
* and its docblock already states the split this comment has to be read
* against: the entry "covers the two paths that serve or rewrite EXISTING data
* — stored rehydration and `os migrate meta`", where the key is NORMALISED to
* `reference` rather than refused, while "the DDL doors above keep guarding
* the third path (metadata handed straight to a driver, around both the gate
* and the stored pass); they are downstream of this entry, not replaced by
* it." This door is one of those DDL doors. Refused when authored, rewritten
* when already at rest, refused again here — three paths, and this comment
* speaks for the third.
*
* Until #11567 this driver read `reference_to` and ONLY `reference_to`, as the
* gate on a `table.foreign(name).references('id')`. So one key had TWO doors
* with opposite answers: the authoring door refused it, while the DDL door
Expand Down
Loading