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
5 changes: 5 additions & 0 deletions .changeset/nosql-index-unique-scope-docs.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
---
'@objectstack/spec': patch
---

Document why `NoSQLIndexSchema.unique` stays a bare boolean instead of the ADR-0120 unique-scope vocabulary carried by `FieldSchema.unique` and `IndexSchema.unique`: the schema is a raw NoSQL driver-configuration descriptor below the tenancy seam — nothing materializes indexes from it, and the one NoSQL driver that creates indexes (driver-mongodb) consumes the object-level `indexes[]` surface (which already carries the vocabulary) and is explicitly single-tenant (#3724) — so a scope word here would be declarable-but-inert vocabulary (ADR-0078). The `describe()` and docblock now state the deliberate omission and the condition under which `UniqueScopeSchema` should be adopted, so the asymmetry with the other two `unique` surfaces is not mistaken for drift (#11215).
2 changes: 1 addition & 1 deletion content/docs/references/data/driver-nosql.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -150,7 +150,7 @@ const result = AggregationPipelineSchema.parse(data);
| **name** | `string` | ✅ | Index name |
| **type** | `Enum<'single' \| 'compound' \| 'unique' \| 'text' \| 'geospatial' \| 'hashed' \| 'ttl' \| 'sparse'>` | ✅ | Index type |
| **fields** | `{ field: string; order?: Enum<'asc' \| 'desc' \| 'text' \| '2dsphere'> }[]` | ✅ | Fields to index |
| **unique** | `boolean` | optional (default: `false`) | Enforce uniqueness |
| **unique** | `boolean` | optional (default: `false`) | Enforce uniqueness over exactly the listed `fields`. Boolean on purpose — no ADR-0120 scope vocabulary here: this is the raw driver-descriptor layer, below tenancy. The 'organization'/'global' boundary is stated on the authorable surfaces (FieldSchema.unique, IndexSchema.unique) and resolved into physical key columns before a descriptor like this is built, so an organization key part, when there is one, is already a listed field (#11215) |
| **sparse** | `boolean` | optional (default: `false`) | Sparse index |
| **expireAfterSeconds** | `integer` | optional | TTL in seconds |
| **partialFilterExpression** | `Record<string, any>` | optional | Partial index filter |
Expand Down
28 changes: 25 additions & 3 deletions packages/spec/src/data/driver-nosql.zod.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -398,9 +398,31 @@ export const NoSQLIndexSchema = lazySchema(() => z.object({
})).describe('Fields to index'),

/**
* Unique constraint
*/
unique: z.boolean().default(false).describe('Enforce uniqueness'),
* Unique constraint — a bare boolean, DELIBERATELY not the ADR-0120 scope
* vocabulary (`UniqueScopeSchema`'s `boolean | 'global' | 'organization'`,
* carried by `FieldSchema.unique` and `IndexSchema.unique`).
*
* This file is the raw NoSQL driver-configuration descriptor layer, not an
* organization-aware authoring surface. Measured for #11215: nothing in the
* repo parses `NoSQLIndexSchema` or materializes indexes from it (a leaf
* schema — no runtime, kernel, or driver import), and the one NoSQL driver
* that does create indexes (driver-mongodb's `syncCollectionSchema`)
* consumes the object-level `indexes[]` surface — `IndexSchema`, which
* already carries the scope vocabulary — and is explicitly single-tenant
* (#3724), injecting no organization key part. The business boundary of a
* unique constraint ('organization' vs 'global') is stated on those
* authorable surfaces and resolved into physical key columns ABOVE this
* layer; by the time a descriptor like this one reaches a NoSQL engine, the
* organization key part — when there is one — is already a listed entry in
* `fields`. A scope word here would have no consumer to honor it, which is
* exactly the declarable-but-inert vocabulary ADR-0078 forbids. So the
* asymmetry with the other two `unique` surfaces is deliberate, not drift.
* If a NoSQL driver ever grows row-level tenancy and starts materializing
* THIS shape against organization-scoped collections, adopt
* `UniqueScopeSchema` here (import it — never fork the union) in the same
* change.
*/
unique: z.boolean().default(false).describe("Enforce uniqueness over exactly the listed `fields`. Boolean on purpose — no ADR-0120 scope vocabulary here: this is the raw driver-descriptor layer, below tenancy. The 'organization'/'global' boundary is stated on the authorable surfaces (FieldSchema.unique, IndexSchema.unique) and resolved into physical key columns before a descriptor like this is built, so an organization key part, when there is one, is already a listed field (#11215)"),

/**
* Sparse index (only index documents with the field)
Expand Down
Loading