@prisma-next/family-sql 0.14.0-dev.3 → 0.14.0-dev.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/{control-adapter-Cmw9LvEP.d.mts → control-adapter-B2q9WN1V.d.mts} +13 -5
  2. package/dist/{control-adapter-Cmw9LvEP.d.mts.map → control-adapter-B2q9WN1V.d.mts.map} +1 -1
  3. package/dist/control-adapter.d.mts +1 -1
  4. package/dist/control.d.mts +2 -2
  5. package/dist/control.d.mts.map +1 -1
  6. package/dist/control.mjs +51 -12
  7. package/dist/control.mjs.map +1 -1
  8. package/dist/ir.d.mts +9 -6
  9. package/dist/ir.d.mts.map +1 -1
  10. package/dist/ir.mjs +1 -1
  11. package/dist/migration.d.mts +1 -1
  12. package/dist/schema-verify.d.mts +2 -2
  13. package/dist/schema-verify.mjs +1 -1
  14. package/dist/{sql-contract-serializer-BR2vC7Z-.mjs → sql-contract-serializer-CYtXg_zs.mjs} +17 -20
  15. package/dist/sql-contract-serializer-CYtXg_zs.mjs.map +1 -0
  16. package/dist/{types-kgstZ_Zd.d.mts → types-BxsFkHYv.d.mts} +4 -4
  17. package/dist/{types-kgstZ_Zd.d.mts.map → types-BxsFkHYv.d.mts.map} +1 -1
  18. package/dist/{verify-sql-schema-thU-jKpf.d.mts → verify-sql-schema-B8uEjw2s.d.mts} +2 -2
  19. package/dist/{verify-sql-schema-thU-jKpf.d.mts.map → verify-sql-schema-B8uEjw2s.d.mts.map} +1 -1
  20. package/dist/{verify-sql-schema-xT4udQLQ.mjs → verify-sql-schema-CEY7b78t.mjs} +28 -22
  21. package/dist/verify-sql-schema-CEY7b78t.mjs.map +1 -0
  22. package/package.json +21 -22
  23. package/src/core/control-adapter.ts +19 -2
  24. package/src/core/control-instance.ts +69 -4
  25. package/src/core/ir/sql-contract-serializer-base.ts +23 -55
  26. package/src/core/ir/sql-contract-serializer.ts +5 -7
  27. package/src/core/migrations/contract-to-schema-ir.ts +7 -5
  28. package/src/core/migrations/field-event-planner.ts +8 -3
  29. package/src/core/psl-contract-infer/sql-schema-ir-to-psl-ast.ts +2 -2
  30. package/src/core/schema-verify/verify-sql-schema.ts +16 -12
  31. package/dist/sql-contract-serializer-BR2vC7Z-.mjs.map +0 -1
  32. package/dist/test-utils.d.mts +0 -2
  33. package/dist/test-utils.mjs +0 -2
  34. package/dist/verify-sql-schema-xT4udQLQ.mjs.map +0 -1
  35. package/src/exports/test-utils.ts +0 -9
@@ -6,18 +6,15 @@ import {
6
6
  type AnyEntityKindDescriptor,
7
7
  hydrateNamespaceEntities,
8
8
  type Namespace,
9
- NamespaceBase,
10
- UNBOUND_NAMESPACE_ID,
11
9
  } from '@prisma-next/framework-components/ir';
12
10
  import { sqlContractCanonicalizationHooks } from '@prisma-next/sql-contract/canonicalization-hooks';
13
11
  import { composeSqlEntityKinds } from '@prisma-next/sql-contract/entity-kinds';
14
12
  import {
15
- buildSqlNamespace,
16
- type SqlNamespaceTablesInput,
13
+ isMaterializedSqlNamespace,
14
+ type SqlNamespaceInput,
17
15
  SqlStorage,
18
16
  type SqlStorageInput,
19
17
  type SqlStorageTypeEntry,
20
- SqlUnboundNamespace,
21
18
  } from '@prisma-next/sql-contract/types';
22
19
  import {
23
20
  createSqlContractSchema,
@@ -120,77 +117,48 @@ export abstract class SqlContractSerializerBase<TContract extends Contract<SqlSt
120
117
  'structural',
121
118
  );
122
119
  }
123
- const hydratedNamespaces = this.hydrateSqlNamespaceMap(rawNamespaces);
124
- // Compatibility shim: production code that addresses `__unbound__` for table
125
- // metadata lookups (collection-contract, query-plan-mutations, model-accessor,
126
- // query-plan-meta, where-binding) uses optional chaining and tolerates absence,
127
- // but runtime-qualification (TML-2605) has not yet landed cross-namespace table
128
- // routing. Injecting the empty singleton here keeps helpers that augment the
129
- // deserialized JSON (e.g. buildMixedPolyContract) working by providing a slot to
130
- // write into. Once runtime-qualification routes table lookups by namespace, this
131
- // shim should be removed.
132
- //
133
- // TML-2916: the shim only fires when the target's default namespace IS unbound
134
- // (SQLite, Mongo). On Postgres (`defaultNamespaceId === 'public'`) injecting an
135
- // empty `__unbound__` slot violates ADR 223 — un-namespaced PG models belong in
136
- // `public`, not `__unbound__`.
137
- const withInjectedUnbound =
138
- this.defaultNamespaceId === UNBOUND_NAMESPACE_ID
139
- ? {
140
- ...hydratedNamespaces,
141
- [UNBOUND_NAMESPACE_ID]:
142
- hydratedNamespaces[UNBOUND_NAMESPACE_ID] ?? SqlUnboundNamespace.instance,
143
- }
144
- : hydratedNamespaces;
120
+ const hydratedNamespaces = this.hydrateSqlNamespaceMap(
121
+ blindCast<
122
+ Readonly<Record<string, Record<string, unknown>>>,
123
+ 'parseSqlContractStructure validated raw JSON; namespace entries are plain objects, not SqlNamespace instances.'
124
+ >(rawNamespaces),
125
+ );
145
126
 
146
127
  return {
147
128
  ...validated,
148
129
  storage: new SqlStorage({
149
130
  storageHash: validated.storage.storageHash,
150
131
  ...ifDefined('types', hydratedTypes),
151
- // Cast narrows the result of hydrateSqlNamespaceMap from the wider
152
- // framework `Namespace` to the SQL-family `SqlNamespace`.
153
132
  namespaces: blindCast<
154
133
  SqlStorageInput['namespaces'],
155
- 'hydrateSqlNamespaceMap builds each namespace through the SQL family concretions (SqlBoundNamespace / target schema), so every value is a SqlNamespace; the framework return type only promises the base Namespace.'
156
- >(withInjectedUnbound),
134
+ 'hydrateSqlNamespaceMap builds each namespace through the target serializer override, so every value is a SqlNamespace; the framework return type only promises the base Namespace.'
135
+ >(hydratedNamespaces),
157
136
  }),
158
137
  };
159
138
  }
160
139
 
161
- protected abstract get defaultNamespaceId(): string;
162
-
163
140
  protected hydrateSqlNamespaceMap(
164
- namespaces: Readonly<Record<string, Namespace | Record<string, unknown>>>,
141
+ namespaces: Readonly<Record<string, Record<string, unknown>>>,
165
142
  ): Readonly<Record<string, Namespace>> {
166
143
  return Object.fromEntries(
167
144
  Object.entries(namespaces).map(([nsId, namespaceEntryRaw]) => {
168
- // Raw entries passed structural validation; hydrate materialises family IR class instances.
169
145
  const namespaceHydrated = this.hydrateSqlNamespaceEntry(nsId, namespaceEntryRaw);
170
- const namespaceMaterialised =
171
- namespaceHydrated instanceof NamespaceBase
172
- ? namespaceHydrated
173
- : buildSqlNamespace(
174
- blindCast<
175
- SqlNamespaceTablesInput,
176
- 'hydrateSqlNamespaceEntry returns SqlNamespaceTablesInput when raw is not a NamespaceBase'
177
- >(namespaceHydrated),
178
- );
179
- return [nsId, namespaceMaterialised];
146
+ if (!isMaterializedSqlNamespace(namespaceHydrated)) {
147
+ throw new Error(
148
+ `Target serializer bug: hydrateSqlNamespaceEntry for namespace "${nsId}" returned a non-NamespaceBase value. Override hydrateSqlNamespaceEntry to produce a target namespace concretion.`,
149
+ );
150
+ }
151
+ return [nsId, namespaceHydrated];
180
152
  }),
181
153
  );
182
154
  }
183
155
 
184
156
  protected hydrateSqlNamespaceEntry(
185
157
  nsId: string,
186
- raw: Namespace | Record<string, unknown>,
187
- ): Namespace | SqlNamespaceTablesInput {
188
- if (raw instanceof NamespaceBase) {
189
- return raw;
190
- }
191
- const rawRecord = isPlainRecord(raw) ? raw : {};
192
- const id = typeof rawRecord['id'] === 'string' ? rawRecord['id'] : nsId;
193
- const parsed = NamespaceRawSchema({ ...rawRecord, id });
158
+ raw: Record<string, unknown>,
159
+ ): Namespace | SqlNamespaceInput {
160
+ const id = typeof raw['id'] === 'string' ? raw['id'] : nsId;
161
+ const parsed = NamespaceRawSchema({ ...raw, id });
194
162
  if (parsed instanceof type.errors) {
195
163
  const messages = parsed.map((p: { message: string }) => p.message).join('; ');
196
164
  throw new ContractValidationError(`Namespace hydration failed: ${messages}`, 'structural');
@@ -211,8 +179,8 @@ export abstract class SqlContractSerializerBase<TContract extends Contract<SqlSt
211
179
  }
212
180
 
213
181
  return blindCast<
214
- SqlNamespaceTablesInput,
215
- 'entriesOutput holds the hydrated SQL entity-kind maps (table always present); this wraps them as the SqlNamespaceTablesInput the family createNamespace consumes.'
182
+ SqlNamespaceInput,
183
+ 'entriesOutput holds the hydrated SQL entity-kind maps (table always present); this wraps them as the SqlNamespaceInput the target createNamespace consumes.'
216
184
  >({
217
185
  id,
218
186
  entries: entriesOutput,
@@ -1,5 +1,4 @@
1
1
  import type { Contract } from '@prisma-next/contract/types';
2
- import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
3
2
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
4
3
  import { SqlContractSerializerBase } from './sql-contract-serializer-base';
5
4
 
@@ -11,15 +10,14 @@ import { SqlContractSerializerBase } from './sql-contract-serializer-base';
11
10
  * codec-typed envelope wire a target-specific subclass with a populated
12
11
  * registry (see Postgres). Family-level call sites instantiate this
13
12
  * default directly when no target serializer is supplied.
13
+ *
14
+ * Because this serializer has no target concretion, deserialization of
15
+ * contracts that include namespace entries from JSON will throw unless
16
+ * the caller provides pre-hydrated `NamespaceBase` instances. Production
17
+ * paths always supply a target-specific serializer.
14
18
  */
15
19
  export class SqlContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {
16
20
  constructor() {
17
21
  super(new Map());
18
22
  }
19
-
20
- // Family-level fallback when no target descriptor is wired in. Preserves the
21
- // pre-TML-2916 compatibility-shim behaviour for the unbound slot.
22
- protected override get defaultNamespaceId(): string {
23
- return UNBOUND_NAMESPACE_ID;
24
- }
25
23
  }
@@ -4,10 +4,11 @@ import {
4
4
  type CheckConstraint,
5
5
  type ForeignKey,
6
6
  type Index,
7
+ isStorageTable,
7
8
  isStorageTypeInstance,
8
9
  type SqlStorage,
9
10
  type StorageColumn,
10
- StorageTable,
11
+ type StorageTable,
11
12
  type StorageTypeInstance,
12
13
  type UniqueConstraint,
13
14
  } from '@prisma-next/sql-contract/types';
@@ -82,13 +83,14 @@ function convertColumn(
82
83
  // typeRef and produces `"vector(1536)"` — making diffs on the same
83
84
  // contract falsely report a `type_mismatch`.
84
85
  const resolved = resolveColumnTypeMetadata(column, storageTypes);
85
- const nativeType = expandNativeType
86
+ const baseNativeType = expandNativeType
86
87
  ? expandNativeType({
87
88
  nativeType: resolved.nativeType,
88
89
  codecId: resolved.codecId,
89
90
  ...ifDefined('typeParams', resolved.typeParams),
90
91
  })
91
92
  : resolved.nativeType;
93
+ const nativeType = column.many ? `${baseNativeType}[]` : baseNativeType;
92
94
  return {
93
95
  name,
94
96
  nativeType,
@@ -303,7 +305,7 @@ export function detectDestructiveChanges(
303
305
 
304
306
  for (const tableName of Object.keys(fromTables)) {
305
307
  const toTableRaw = toNs?.entries.table?.[tableName];
306
- if (!(toTableRaw instanceof StorageTable)) {
308
+ if (!isStorageTable(toTableRaw)) {
307
309
  conflicts.push({
308
310
  kind: 'tableRemoved',
309
311
  summary: `Table "${tableName}" was removed`,
@@ -313,7 +315,7 @@ export function detectDestructiveChanges(
313
315
  const toTable = toTableRaw;
314
316
 
315
317
  const fromTableRaw = fromTables[tableName];
316
- if (!(fromTableRaw instanceof StorageTable)) continue;
318
+ if (!isStorageTable(fromTableRaw)) continue;
317
319
  const fromTable = fromTableRaw;
318
320
 
319
321
  for (const columnName of Object.keys(fromTable.columns)) {
@@ -377,7 +379,7 @@ export function contractToSchemaIR(
377
379
  const tables: Record<string, SqlTableIR> = {};
378
380
  for (const ns of Object.values(storage.namespaces)) {
379
381
  for (const [tableName, tableDefRaw] of Object.entries(ns.entries.table ?? {})) {
380
- if (!(tableDefRaw instanceof StorageTable)) {
382
+ if (!isStorageTable(tableDefRaw)) {
381
383
  throw new Error(
382
384
  `contractToSchemaIR: expected StorageTable at namespaces.${ns.id}.entries.table.${tableName}`,
383
385
  );
@@ -24,7 +24,12 @@
24
24
 
25
25
  import type { Contract } from '@prisma-next/contract/types';
26
26
  import type { OpFactoryCall } from '@prisma-next/framework-components/control';
27
- import { type SqlStorage, type StorageColumn, StorageTable } from '@prisma-next/sql-contract/types';
27
+ import {
28
+ isStorageTable,
29
+ type SqlStorage,
30
+ type StorageColumn,
31
+ type StorageTable,
32
+ } from '@prisma-next/sql-contract/types';
28
33
  import type { CodecControlHooks, FieldEvent, FieldEventContext } from './types';
29
34
 
30
35
  export interface PlanFieldEventOperationsOptions {
@@ -88,8 +93,8 @@ export function planFieldEventOperations(
88
93
  for (const tableName of tableNames) {
89
94
  const priorTableRaw = priorTables?.[tableName];
90
95
  const newTableRaw = newTables?.[tableName];
91
- const priorTable = priorTableRaw instanceof StorageTable ? priorTableRaw : undefined;
92
- const newTable = newTableRaw instanceof StorageTable ? newTableRaw : undefined;
96
+ const priorTable = isStorageTable(priorTableRaw) ? priorTableRaw : undefined;
97
+ const newTable = isStorageTable(newTableRaw) ? newTableRaw : undefined;
93
98
  const fieldNames = unionSorted(
94
99
  priorTable ? Object.keys(priorTable.columns) : [],
95
100
  newTable ? Object.keys(newTable.columns) : [],
@@ -305,7 +305,7 @@ function buildScalarField(
305
305
  name: fieldName,
306
306
  typeName: `Unsupported("${escapePslString(resolution.nativeType)}")`,
307
307
  optional: column.nullable,
308
- list: false,
308
+ list: column.many === true,
309
309
  attributes: attrs,
310
310
  span: SYNTHETIC_SPAN,
311
311
  };
@@ -354,7 +354,7 @@ function buildScalarField(
354
354
  name: fieldName,
355
355
  typeName,
356
356
  optional: column.nullable,
357
- list: false,
357
+ list: column.many === true,
358
358
  attributes,
359
359
  span: SYNTHETIC_SPAN,
360
360
  };
@@ -18,10 +18,11 @@ import type {
18
18
  } from '@prisma-next/framework-components/control';
19
19
 
20
20
  import {
21
+ isStorageTable,
21
22
  isStorageTypeInstance,
22
23
  type SqlStorage,
23
24
  type StorageColumn,
24
- StorageTable,
25
+ type StorageTable,
25
26
  type StorageTypeInstance,
26
27
  } from '@prisma-next/sql-contract/types';
27
28
  import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
@@ -236,6 +237,7 @@ export function verifySqlSchema(options: VerifySqlSchemaOptions): VerifyDatabase
236
237
  },
237
238
  schema: {
238
239
  issues,
240
+ schemaDiffIssues: [],
239
241
  root,
240
242
  counts,
241
243
  },
@@ -297,7 +299,7 @@ function verifySchemaTables(options: {
297
299
  const ns = contract.storage.namespaces[namespaceId];
298
300
  if (!ns) continue;
299
301
  for (const [tableName, contractTableRaw] of Object.entries(ns.entries.table ?? {})) {
300
- if (!(contractTableRaw instanceof StorageTable)) {
302
+ if (!isStorageTable(contractTableRaw)) {
301
303
  throw new Error(
302
304
  `verifySqlSchema: expected StorageTable at storage.namespaces.${namespaceId}.entries.table.${tableName}`,
303
305
  );
@@ -790,8 +792,9 @@ function verifyColumn(options: {
790
792
  tableName,
791
793
  columnName,
792
794
  });
793
- const schemaNativeType =
795
+ const schemaBaseNativeType =
794
796
  normalizeNativeType?.(schemaColumn.nativeType) ?? schemaColumn.nativeType;
797
+ const schemaNativeType = schemaColumn.many ? `${schemaBaseNativeType}[]` : schemaBaseNativeType;
795
798
 
796
799
  const typesMatch = contractNativeType === schemaNativeType;
797
800
 
@@ -1144,19 +1147,20 @@ function renderExpectedNativeType(
1144
1147
  context,
1145
1148
  );
1146
1149
 
1150
+ let baseType: string;
1151
+
1147
1152
  // If no typeParams or codecId, return the base native type
1148
1153
  if (!typeParams || !codecId) {
1149
- return nativeType;
1150
- }
1151
-
1152
- // Try to use the codec's expandNativeType hook if available
1153
- const hooks = codecHooks.get(codecId);
1154
- if (hooks?.expandNativeType) {
1155
- return hooks.expandNativeType({ nativeType, codecId, typeParams });
1154
+ baseType = nativeType;
1155
+ } else {
1156
+ // Try to use the codec's expandNativeType hook if available
1157
+ const hooks = codecHooks.get(codecId);
1158
+ baseType = hooks?.expandNativeType
1159
+ ? hooks.expandNativeType({ nativeType, codecId, typeParams })
1160
+ : nativeType;
1156
1161
  }
1157
1162
 
1158
- // Fallback: return base native type if no hook is available
1159
- return nativeType;
1163
+ return contractColumn.many ? `${baseType}[]` : baseType;
1160
1164
  }
1161
1165
 
1162
1166
  function resolveContractColumnTypeMetadata(
@@ -1 +0,0 @@
1
- {"version":3,"file":"sql-contract-serializer-BR2vC7Z-.mjs","names":[],"sources":["../src/core/ir/sql-contract-serializer-base.ts","../src/core/ir/sql-contract-serializer.ts"],"sourcesContent":["import { ContractValidationError } from '@prisma-next/contract/contract-validation-error';\nimport { isPlainRecord } from '@prisma-next/contract/is-plain-record';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { ContractSerializer } from '@prisma-next/framework-components/control';\nimport {\n type AnyEntityKindDescriptor,\n hydrateNamespaceEntities,\n type Namespace,\n NamespaceBase,\n UNBOUND_NAMESPACE_ID,\n} from '@prisma-next/framework-components/ir';\nimport { sqlContractCanonicalizationHooks } from '@prisma-next/sql-contract/canonicalization-hooks';\nimport { composeSqlEntityKinds } from '@prisma-next/sql-contract/entity-kinds';\nimport {\n buildSqlNamespace,\n type SqlNamespaceTablesInput,\n SqlStorage,\n type SqlStorageInput,\n type SqlStorageTypeEntry,\n SqlUnboundNamespace,\n} from '@prisma-next/sql-contract/types';\nimport {\n createSqlContractSchema,\n validateSqlContractFully,\n} from '@prisma-next/sql-contract/validators';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { JsonObject } from '@prisma-next/utils/json';\nimport { type Type, type } from 'arktype';\n\nconst NamespaceRawSchema = type({\n id: 'string',\n 'kind?': 'string',\n entries: type({\n '+': 'ignore',\n }),\n});\n\nexport type SqlEntityHydrationFactory = (entry: unknown) => unknown;\n\n/**\n * SQL family `ContractSerializer` abstract base. Carries the SQL-shared\n * deserialization pipeline:\n *\n * 1. `parseSqlContractStructure` validates the on-disk JSON envelope\n * against the SQL contract arktype schema (`validateSqlContractFully`)\n * and returns the validated flat-data shape.\n * 2. `hydrateSqlStorage` walks the validated `storage` subtree and\n * constructs the family-shared SQL Contract IR class hierarchy\n * (`SqlStorage` -> `StorageTable` -> `StorageColumn` / `PrimaryKey`\n * / …). The rest of the contract envelope is JSON-clean primitive\n * data and passes through unchanged.\n * 3. `constructTargetContract` is the target-specific extension hook;\n * defaults to identity. Targets that need to attach target-only\n * fields (e.g. target-specific derived storage fields) override it.\n *\n * Default `serializeContract` is identity over the contract — concrete\n * SQL targets ship JSON-clean class instances, so the contract value\n * can be stringified directly. The non-enumerable family-level `kind`\n * discriminator on `SqlNode` instances stays out of the persisted\n * envelope automatically. Targets that need to canonicalize on the way\n * out (key ordering, dropping computed-only fields) override\n * `serializeContract` directly.\n */\nexport abstract class SqlContractSerializerBase<TContract extends Contract<SqlStorage>>\n implements ContractSerializer<TContract>\n{\n private readonly contractSchema: Type<unknown> | undefined;\n private readonly entryKinds: ReadonlyMap<string, AnyEntityKindDescriptor>;\n\n constructor(\n protected readonly entityHydrationRegistry: ReadonlyMap<\n string,\n SqlEntityHydrationFactory\n > = new Map(),\n packEntityKinds: readonly AnyEntityKindDescriptor[] = [],\n ) {\n this.entryKinds = composeSqlEntityKinds(packEntityKinds);\n this.contractSchema =\n packEntityKinds.length > 0 ? createSqlContractSchema(this.entryKinds) : undefined;\n }\n\n deserializeContract<T extends TContract = TContract>(json: unknown): T {\n const validated = this.parseSqlContractStructure(json);\n const hydrated = this.hydrateSqlStorage(validated);\n return this.constructTargetContract(hydrated) as T;\n }\n\n serializeContract(contract: TContract): JsonObject {\n return contract as unknown as JsonObject;\n }\n\n shouldPreserveEmpty = sqlContractCanonicalizationHooks.shouldPreserveEmpty;\n\n sortStorage = sqlContractCanonicalizationHooks.sortStorage;\n\n protected parseSqlContractStructure(json: unknown): Contract<SqlStorage> {\n return validateSqlContractFully<Contract<SqlStorage>>(\n json,\n this.contractSchema !== undefined ? { contractSchema: this.contractSchema } : undefined,\n );\n }\n\n protected hydrateSqlStorage(validated: Contract<SqlStorage>): Contract<SqlStorage> {\n const types = validated.storage.types;\n const hydratedTypes =\n types !== undefined\n ? Object.fromEntries(\n Object.entries(types).map(([name, entry]) => [\n name,\n this.hydrateStorageTypeEntry(entry),\n ]),\n )\n : undefined;\n\n const rawNamespaces = validated.storage.namespaces;\n if (rawNamespaces === undefined) {\n throw new ContractValidationError(\n 'Contract storage.namespaces is required after structural validation',\n 'structural',\n );\n }\n const hydratedNamespaces = this.hydrateSqlNamespaceMap(rawNamespaces);\n // Compatibility shim: production code that addresses `__unbound__` for table\n // metadata lookups (collection-contract, query-plan-mutations, model-accessor,\n // query-plan-meta, where-binding) uses optional chaining and tolerates absence,\n // but runtime-qualification (TML-2605) has not yet landed cross-namespace table\n // routing. Injecting the empty singleton here keeps helpers that augment the\n // deserialized JSON (e.g. buildMixedPolyContract) working by providing a slot to\n // write into. Once runtime-qualification routes table lookups by namespace, this\n // shim should be removed.\n //\n // TML-2916: the shim only fires when the target's default namespace IS unbound\n // (SQLite, Mongo). On Postgres (`defaultNamespaceId === 'public'`) injecting an\n // empty `__unbound__` slot violates ADR 223 — un-namespaced PG models belong in\n // `public`, not `__unbound__`.\n const withInjectedUnbound =\n this.defaultNamespaceId === UNBOUND_NAMESPACE_ID\n ? {\n ...hydratedNamespaces,\n [UNBOUND_NAMESPACE_ID]:\n hydratedNamespaces[UNBOUND_NAMESPACE_ID] ?? SqlUnboundNamespace.instance,\n }\n : hydratedNamespaces;\n\n return {\n ...validated,\n storage: new SqlStorage({\n storageHash: validated.storage.storageHash,\n ...ifDefined('types', hydratedTypes),\n // Cast narrows the result of hydrateSqlNamespaceMap from the wider\n // framework `Namespace` to the SQL-family `SqlNamespace`.\n namespaces: blindCast<\n SqlStorageInput['namespaces'],\n 'hydrateSqlNamespaceMap builds each namespace through the SQL family concretions (SqlBoundNamespace / target schema), so every value is a SqlNamespace; the framework return type only promises the base Namespace.'\n >(withInjectedUnbound),\n }),\n };\n }\n\n protected abstract get defaultNamespaceId(): string;\n\n protected hydrateSqlNamespaceMap(\n namespaces: Readonly<Record<string, Namespace | Record<string, unknown>>>,\n ): Readonly<Record<string, Namespace>> {\n return Object.fromEntries(\n Object.entries(namespaces).map(([nsId, namespaceEntryRaw]) => {\n // Raw entries passed structural validation; hydrate materialises family IR class instances.\n const namespaceHydrated = this.hydrateSqlNamespaceEntry(nsId, namespaceEntryRaw);\n const namespaceMaterialised =\n namespaceHydrated instanceof NamespaceBase\n ? namespaceHydrated\n : buildSqlNamespace(\n blindCast<\n SqlNamespaceTablesInput,\n 'hydrateSqlNamespaceEntry returns SqlNamespaceTablesInput when raw is not a NamespaceBase'\n >(namespaceHydrated),\n );\n return [nsId, namespaceMaterialised];\n }),\n );\n }\n\n protected hydrateSqlNamespaceEntry(\n nsId: string,\n raw: Namespace | Record<string, unknown>,\n ): Namespace | SqlNamespaceTablesInput {\n if (raw instanceof NamespaceBase) {\n return raw;\n }\n const rawRecord = isPlainRecord(raw) ? raw : {};\n const id = typeof rawRecord['id'] === 'string' ? rawRecord['id'] : nsId;\n const parsed = NamespaceRawSchema({ ...rawRecord, id });\n if (parsed instanceof type.errors) {\n const messages = parsed.map((p: { message: string }) => p.message).join('; ');\n throw new ContractValidationError(`Namespace hydration failed: ${messages}`, 'structural');\n }\n const entriesRaw = parsed.entries;\n const rawEntriesMap = isPlainRecord(entriesRaw) ? entriesRaw : {};\n\n const entriesInput: Record<string, Readonly<Record<string, unknown>>> = {};\n for (const [key, innerMap] of Object.entries(rawEntriesMap)) {\n entriesInput[key] = isPlainRecord(innerMap) ? innerMap : Object.freeze({});\n }\n\n const entriesOutput = hydrateNamespaceEntities(entriesInput, this.entryKinds, 'fail', id);\n\n // Always ensure a 'table' key is present (may be empty).\n if (!Object.hasOwn(entriesOutput, 'table')) {\n entriesOutput['table'] = {};\n }\n\n return blindCast<\n SqlNamespaceTablesInput,\n 'entriesOutput holds the hydrated SQL entity-kind maps (table always present); this wraps them as the SqlNamespaceTablesInput the family createNamespace consumes.'\n >({\n id,\n entries: entriesOutput,\n });\n }\n\n protected hydrateStorageTypeEntry(entry: SqlStorageTypeEntry): SqlStorageTypeEntry {\n if (typeof entry !== 'object' || entry === null) {\n return entry;\n }\n const kind = (entry as { kind?: unknown }).kind;\n if (typeof kind !== 'string') {\n return entry;\n }\n const factory = this.entityHydrationRegistry.get(kind);\n if (factory === undefined) {\n return entry;\n }\n return blindCast<\n SqlStorageTypeEntry,\n 'entity registry factory returns SqlStorageTypeEntry for storage.types entries'\n >(factory(entry));\n }\n\n protected constructTargetContract(hydrated: Contract<SqlStorage>): TContract {\n return hydrated as TContract;\n }\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { SqlContractSerializerBase } from './sql-contract-serializer-base';\n\n/**\n * Default SQL family `ContractSerializer` concretion. Inherits the\n * full SQL-shared deserialization pipeline (structural validation +\n * IR-class hydration) without pack-registered `storage.types`\n * hydration factories — targets that emit polymorphic JSON outside the\n * codec-typed envelope wire a target-specific subclass with a populated\n * registry (see Postgres). Family-level call sites instantiate this\n * default directly when no target serializer is supplied.\n */\nexport class SqlContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {\n constructor() {\n super(new Map());\n }\n\n // Family-level fallback when no target descriptor is wired in. Preserves the\n // pre-TML-2916 compatibility-shim behaviour for the unbound slot.\n protected override get defaultNamespaceId(): string {\n return UNBOUND_NAMESPACE_ID;\n }\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import { extractCodecTypeImports, extractComponentIds, extractQueryOperationTypeImports } from "@prisma-next/framework-components/control";
2
- export { extractCodecTypeImports, extractComponentIds, extractQueryOperationTypeImports };
@@ -1,2 +0,0 @@
1
- import { extractCodecTypeImports, extractComponentIds, extractQueryOperationTypeImports } from "@prisma-next/framework-components/control";
2
- export { extractCodecTypeImports, extractComponentIds, extractQueryOperationTypeImports };