@prisma-next/family-sql 0.13.0-dev.34 → 0.13.0-dev.36

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.
package/dist/control.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { i as sqlFamilyPslBlockDescriptors, n as sqlFamilyAuthoringFieldPresets, r as sqlFamilyEntityTypes, t as sqlFamilyAuthoringTypes } from "./authoring-type-constructors-CjFfO6LM.mjs";
2
- import { t as SqlContractSerializer } from "./sql-contract-serializer-D6-28zKd.mjs";
2
+ import { t as SqlContractSerializer } from "./sql-contract-serializer-BKSX9JhA.mjs";
3
3
  import { a as contractToSchemaIR, c as extractCodecControlHooks, o as detectDestructiveChanges, s as resolveValueSetValues, t as verifySqlSchema } from "./verify-sql-schema-xT4udQLQ.mjs";
4
4
  import { t as collectSupportedCodecTypeIds } from "./verify-C-G0obRm.mjs";
5
5
  import { n as temporalAuthoringPresets, r as timestampNowControlDescriptor } from "./timestamp-now-generator-CloimujU.mjs";
package/dist/ir.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { ContractSerializer, SchemaIssue, SchemaVerifier, SchemaVerifyOptions, SchemaVerifyResult } from "@prisma-next/framework-components/control";
2
- import { Namespace } from "@prisma-next/framework-components/ir";
2
+ import { AnyEntityKindDescriptor, Namespace } from "@prisma-next/framework-components/ir";
3
3
  import { SqlNamespaceTablesInput, SqlStorage, SqlStorageTypeEntry } from "@prisma-next/sql-contract/types";
4
- import { Type } from "arktype";
5
4
  import { Contract } from "@prisma-next/contract/types";
6
5
  import { JsonObject } from "@prisma-next/utils/json";
7
6
 
@@ -34,7 +33,8 @@ type SqlEntityHydrationFactory = (entry: unknown) => unknown;
34
33
  declare abstract class SqlContractSerializerBase<TContract extends Contract<SqlStorage>> implements ContractSerializer<TContract> {
35
34
  protected readonly entityHydrationRegistry: ReadonlyMap<string, SqlEntityHydrationFactory>;
36
35
  private readonly contractSchema;
37
- constructor(entityHydrationRegistry?: ReadonlyMap<string, SqlEntityHydrationFactory>, validatorRegistry?: ReadonlyMap<string, Type<unknown>>);
36
+ private readonly entryKinds;
37
+ constructor(entityHydrationRegistry?: ReadonlyMap<string, SqlEntityHydrationFactory>, packEntityKinds?: readonly AnyEntityKindDescriptor[]);
38
38
  deserializeContract<T extends TContract = TContract>(json: unknown): T;
39
39
  serializeContract(contract: TContract): JsonObject;
40
40
  shouldPreserveEmpty: import("@prisma-next/contract/hashing").PreserveEmptyPredicate;
@@ -43,7 +43,6 @@ declare abstract class SqlContractSerializerBase<TContract extends Contract<SqlS
43
43
  protected hydrateSqlStorage(validated: Contract<SqlStorage>): Contract<SqlStorage>;
44
44
  protected hydrateSqlNamespaceMap(namespaces: Readonly<Record<string, Namespace | Record<string, unknown>>>): Readonly<Record<string, Namespace>>;
45
45
  protected hydrateSqlNamespaceEntry(nsId: string, raw: Namespace | Record<string, unknown>): Namespace | SqlNamespaceTablesInput;
46
- protected hydrateEntriesKind(key: string, innerMap: unknown): Record<string, unknown> | undefined;
47
46
  protected hydrateStorageTypeEntry(entry: SqlStorageTypeEntry): SqlStorageTypeEntry;
48
47
  protected constructTargetContract(hydrated: Contract<SqlStorage>): TContract;
49
48
  }
package/dist/ir.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ir.d.mts","names":[],"sources":["../src/core/ir/sql-contract-serializer-base.ts","../src/core/ir/sql-contract-serializer.ts","../src/core/ir/sql-schema-verifier-base.ts"],"mappings":";;;;;;;;KA2CY,yBAAA,IAA6B,KAAc;;AAAvD;;;;AAAuD;AA0BvD;;;;;;;;;;;;;;;;;;uBAAsB,yBAAA,mBAA4C,QAAA,CAAS,UAAA,cAC9D,kBAAA,CAAmB,SAAA;EAAA,mBAKT,uBAAA,EAAyB,WAAA,SAE1C,yBAAA;EAAA,iBALa,cAAA;cAGI,uBAAA,GAAyB,WAAA,SAE1C,yBAAA,GAEF,iBAAA,GAAmB,WAAA,SAAoB,IAAA;EAazC,mBAAA,WAA8B,SAAA,GAAY,SAAA,EAAW,IAAA,YAAgB,CAAA;EAMrE,iBAAA,CAAkB,QAAA,EAAU,SAAA,GAAY,UAAA;EAIxC,mBAAA,0CAAmB,sBAAA;EAEnB,WAAA,0CAAW,WAAA;EAAA,UAED,yBAAA,CAA0B,IAAA,YAAgB,QAAA,CAAS,UAAA;EAAA,UAOnD,iBAAA,CAAkB,SAAA,EAAW,QAAA,CAAS,UAAA,IAAc,QAAA,CAAS,UAAA;EAAA,UA6C7D,sBAAA,CACR,UAAA,EAAY,QAAA,CAAS,MAAA,SAAe,SAAA,GAAY,MAAA,sBAC/C,QAAA,CAAS,MAAA,SAAe,SAAA;EAAA,UAmBjB,wBAAA,CACR,IAAA,UACA,GAAA,EAAK,SAAA,GAAY,MAAA,oBAChB,SAAA,GAAY,uBAAA;EAAA,UAqCL,kBAAA,CACR,GAAA,UACA,QAAA,YACC,MAAA;EAAA,UA8CO,uBAAA,CAAwB,KAAA,EAAO,mBAAA,GAAsB,mBAAA;EAAA,UAkBrD,uBAAA,CAAwB,QAAA,EAAU,QAAA,CAAS,UAAA,IAAc,SAAA;AAAA;;;;;;;;AAnPrE;;;;cC9Ba,qBAAA,SAA8B,yBAAA,CAA0B,QAAA,CAAS,UAAA;;;;;;;;;;;;AD8B9E;;;;AAAuD;AA0BvD;;;;;;;;uBE1CsB,qBAAA,gCACT,cAAA,CAAe,SAAA,EAAW,OAAA;EAErC,YAAA,CAAa,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,IAAW,kBAAA;EFiDvB;;;;;;EAAA,mBEpCtB,qBAAA,CACjB,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;EF6DiD;;;;;EAAA,mBEtD1C,sBAAA,CACjB,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;AAAA"}
1
+ {"version":3,"file":"ir.d.mts","names":[],"sources":["../src/core/ir/sql-contract-serializer-base.ts","../src/core/ir/sql-contract-serializer.ts","../src/core/ir/sql-schema-verifier-base.ts"],"mappings":";;;;;;;KAsCY,yBAAA,IAA6B,KAAc;;AAAvD;;;;AAAuD;AA0BvD;;;;;;;;;;;;;;;;;;uBAAsB,yBAAA,mBAA4C,QAAA,CAAS,UAAA,cAC9D,kBAAA,CAAmB,SAAA;EAAA,mBAMT,uBAAA,EAAyB,WAAA,SAE1C,yBAAA;EAAA,iBANa,cAAA;EAAA,iBACA,UAAA;cAGI,uBAAA,GAAyB,WAAA,SAE1C,yBAAA,GAEF,eAAA,YAA0B,uBAAA;EAO5B,mBAAA,WAA8B,SAAA,GAAY,SAAA,EAAW,IAAA,YAAgB,CAAA;EAMrE,iBAAA,CAAkB,QAAA,EAAU,SAAA,GAAY,UAAA;EAIxC,mBAAA,0CAAmB,sBAAA;EAEnB,WAAA,0CAAW,WAAA;EAAA,UAED,yBAAA,CAA0B,IAAA,YAAgB,QAAA,CAAS,UAAA;EAAA,UAOnD,iBAAA,CAAkB,SAAA,EAAW,QAAA,CAAS,UAAA,IAAc,QAAA,CAAS,UAAA;EAAA,UA6C7D,sBAAA,CACR,UAAA,EAAY,QAAA,CAAS,MAAA,SAAe,SAAA,GAAY,MAAA,sBAC/C,QAAA,CAAS,MAAA,SAAe,SAAA;EAAA,UAmBjB,wBAAA,CACR,IAAA,UACA,GAAA,EAAK,SAAA,GAAY,MAAA,oBAChB,SAAA,GAAY,uBAAA;EAAA,UAmCL,uBAAA,CAAwB,KAAA,EAAO,mBAAA,GAAsB,mBAAA;EAAA,UAkBrD,uBAAA,CAAwB,QAAA,EAAU,QAAA,CAAS,UAAA,IAAc,SAAA;AAAA;;;;;;;AA3LrE;;;;AAAuD;cCzB1C,qBAAA,SAA8B,yBAAA,CAA0B,QAAA,CAAS,UAAA;;;;;;;;;;;ADyB9E;;;;AAAuD;AA0BvD;;;;;;;;;uBErCsB,qBAAA,gCACT,cAAA,CAAe,SAAA,EAAW,OAAA;EAErC,YAAA,CAAa,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,IAAW,kBAAA;EFoDlC;;;;;;EAAA,mBEvCX,qBAAA,CACjB,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;EF0DoC;;;;;EAAA,mBEnD7B,sBAAA,CACjB,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;AAAA"}
package/dist/ir.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as SqlContractSerializerBase, t as SqlContractSerializer } from "./sql-contract-serializer-D6-28zKd.mjs";
1
+ import { n as SqlContractSerializerBase, t as SqlContractSerializer } from "./sql-contract-serializer-BKSX9JhA.mjs";
2
2
  //#region src/core/ir/sql-schema-verifier-base.ts
3
3
  /**
4
4
  * SQL family `SchemaVerifier` abstract base. Centralises the SQL-shared
@@ -2,9 +2,11 @@ import { blindCast } from "@prisma-next/utils/casts";
2
2
  import { sqlContractCanonicalizationHooks } from "@prisma-next/sql-contract/canonicalization-hooks";
3
3
  import { ifDefined } from "@prisma-next/utils/defined";
4
4
  import { ContractValidationError } from "@prisma-next/contract/contract-validation-error";
5
- import { NamespaceBase, UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
6
- import { SqlStorage, SqlUnboundNamespace, StorageTable, StorageValueSet, buildSqlNamespace } from "@prisma-next/sql-contract/types";
7
- import { createSqlContractSchema, createSqlEntrySchemaRegistry, validateSqlContractFully } from "@prisma-next/sql-contract/validators";
5
+ import { isPlainRecord } from "@prisma-next/contract/is-plain-record";
6
+ import { NamespaceBase, UNBOUND_NAMESPACE_ID, hydrateNamespaceEntities } from "@prisma-next/framework-components/ir";
7
+ import { composeSqlEntityKinds } from "@prisma-next/sql-contract/entity-kinds";
8
+ import { SqlStorage, SqlUnboundNamespace, buildSqlNamespace } from "@prisma-next/sql-contract/types";
9
+ import { createSqlContractSchema, validateSqlContractFully } from "@prisma-next/sql-contract/validators";
8
10
  import { type } from "arktype";
9
11
  //#region src/core/ir/sql-contract-serializer-base.ts
10
12
  const NamespaceRawSchema = type({
@@ -12,9 +14,6 @@ const NamespaceRawSchema = type({
12
14
  "kind?": "string",
13
15
  entries: type({ "+": "ignore" })
14
16
  });
15
- function isPlainRecord(value) {
16
- return typeof value === "object" && value !== null && !Array.isArray(value);
17
- }
18
17
  /**
19
18
  * SQL family `ContractSerializer` abstract base. Carries the SQL-shared
20
19
  * deserialization pipeline:
@@ -42,9 +41,11 @@ function isPlainRecord(value) {
42
41
  var SqlContractSerializerBase = class {
43
42
  entityHydrationRegistry;
44
43
  contractSchema;
45
- constructor(entityHydrationRegistry = /* @__PURE__ */ new Map(), validatorRegistry = /* @__PURE__ */ new Map()) {
44
+ entryKinds;
45
+ constructor(entityHydrationRegistry = /* @__PURE__ */ new Map(), packEntityKinds = []) {
46
46
  this.entityHydrationRegistry = entityHydrationRegistry;
47
- this.contractSchema = validatorRegistry.size > 0 ? createSqlContractSchema(createSqlEntrySchemaRegistry(validatorRegistry)) : void 0;
47
+ this.entryKinds = composeSqlEntityKinds(packEntityKinds);
48
+ this.contractSchema = packEntityKinds.length > 0 ? createSqlContractSchema(this.entryKinds) : void 0;
48
49
  }
49
50
  deserializeContract(json) {
50
51
  const validated = this.parseSqlContractStructure(json);
@@ -93,32 +94,17 @@ var SqlContractSerializerBase = class {
93
94
  id
94
95
  });
95
96
  if (parsed instanceof type.errors) throw new ContractValidationError(`Namespace hydration failed: ${parsed.map((p) => p.message).join("; ")}`, "structural");
96
- const entriesOutput = {};
97
97
  const entriesRaw = parsed.entries;
98
- if (entriesRaw !== void 0 && typeof entriesRaw === "object" && entriesRaw !== null) {
99
- const rawEntries = entriesRaw;
100
- for (const [key, innerMap] of Object.entries(rawEntries)) {
101
- const hydrated = this.hydrateEntriesKind(key, innerMap);
102
- if (hydrated === void 0) throw new ContractValidationError(`Unknown entries key "${key}" in namespace "${id}"; no hydration factory registered for this entity kind`, "structural");
103
- entriesOutput[key] = hydrated;
104
- }
105
- }
98
+ const rawEntriesMap = isPlainRecord(entriesRaw) ? entriesRaw : {};
99
+ const entriesInput = {};
100
+ for (const [key, innerMap] of Object.entries(rawEntriesMap)) entriesInput[key] = isPlainRecord(innerMap) ? innerMap : Object.freeze({});
101
+ const entriesOutput = hydrateNamespaceEntities(entriesInput, this.entryKinds, "fail", id);
106
102
  if (!Object.hasOwn(entriesOutput, "table")) entriesOutput["table"] = {};
107
103
  return blindCast({
108
104
  id,
109
105
  entries: entriesOutput
110
106
  });
111
107
  }
112
- hydrateEntriesKind(key, innerMap) {
113
- if (key === "table") {
114
- if (innerMap === null || typeof innerMap !== "object" || Array.isArray(innerMap)) return {};
115
- return Object.fromEntries(Object.entries(blindCast(innerMap)).map(([tableName, table]) => [tableName, new StorageTable(blindCast(table))]));
116
- }
117
- if (key === "valueSet") {
118
- if (innerMap === null || typeof innerMap !== "object" || Array.isArray(innerMap)) return {};
119
- return Object.fromEntries(Object.entries(blindCast(innerMap)).map(([vsName, vs]) => [vsName, new StorageValueSet(blindCast(vs))]));
120
- }
121
- }
122
108
  hydrateStorageTypeEntry(entry) {
123
109
  if (typeof entry !== "object" || entry === null) return entry;
124
110
  const kind = entry.kind;
@@ -150,4 +136,4 @@ var SqlContractSerializer = class extends SqlContractSerializerBase {
150
136
  //#endregion
151
137
  export { SqlContractSerializerBase as n, SqlContractSerializer as t };
152
138
 
153
- //# sourceMappingURL=sql-contract-serializer-D6-28zKd.mjs.map
139
+ //# sourceMappingURL=sql-contract-serializer-BKSX9JhA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-contract-serializer-BKSX9JhA.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 const unbound = hydratedNamespaces[UNBOUND_NAMESPACE_ID] ?? SqlUnboundNamespace.instance;\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 >({ ...hydratedNamespaces, [UNBOUND_NAMESPACE_ID]: unbound }),\n }),\n };\n }\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 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"],"mappings":"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"}
package/package.json CHANGED
@@ -1,34 +1,34 @@
1
1
  {
2
2
  "name": "@prisma-next/family-sql",
3
- "version": "0.13.0-dev.34",
3
+ "version": "0.13.0-dev.36",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "SQL family descriptor for Prisma Next",
8
8
  "dependencies": {
9
- "@prisma-next/contract": "0.13.0-dev.34",
10
- "@prisma-next/emitter": "0.13.0-dev.34",
11
- "@prisma-next/framework-components": "0.13.0-dev.34",
12
- "@prisma-next/migration-tools": "0.13.0-dev.34",
13
- "@prisma-next/operations": "0.13.0-dev.34",
14
- "@prisma-next/sql-contract": "0.13.0-dev.34",
15
- "@prisma-next/sql-contract-emitter": "0.13.0-dev.34",
16
- "@prisma-next/sql-contract-ts": "0.13.0-dev.34",
17
- "@prisma-next/sql-operations": "0.13.0-dev.34",
18
- "@prisma-next/sql-relational-core": "0.13.0-dev.34",
19
- "@prisma-next/sql-runtime": "0.13.0-dev.34",
20
- "@prisma-next/sql-schema-ir": "0.13.0-dev.34",
21
- "@prisma-next/utils": "0.13.0-dev.34",
9
+ "@prisma-next/contract": "0.13.0-dev.36",
10
+ "@prisma-next/emitter": "0.13.0-dev.36",
11
+ "@prisma-next/framework-components": "0.13.0-dev.36",
12
+ "@prisma-next/migration-tools": "0.13.0-dev.36",
13
+ "@prisma-next/operations": "0.13.0-dev.36",
14
+ "@prisma-next/sql-contract": "0.13.0-dev.36",
15
+ "@prisma-next/sql-contract-emitter": "0.13.0-dev.36",
16
+ "@prisma-next/sql-contract-ts": "0.13.0-dev.36",
17
+ "@prisma-next/sql-operations": "0.13.0-dev.36",
18
+ "@prisma-next/sql-relational-core": "0.13.0-dev.36",
19
+ "@prisma-next/sql-runtime": "0.13.0-dev.36",
20
+ "@prisma-next/sql-schema-ir": "0.13.0-dev.36",
21
+ "@prisma-next/utils": "0.13.0-dev.36",
22
22
  "arktype": "^2.2.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@prisma-next/driver-postgres": "0.13.0-dev.34",
26
- "@prisma-next/psl-parser": "0.13.0-dev.34",
27
- "@prisma-next/psl-printer": "0.13.0-dev.34",
28
- "@prisma-next/sql-contract-psl": "0.13.0-dev.34",
29
- "@prisma-next/test-utils": "0.13.0-dev.34",
30
- "@prisma-next/tsconfig": "0.13.0-dev.34",
31
- "@prisma-next/tsdown": "0.13.0-dev.34",
25
+ "@prisma-next/driver-postgres": "0.13.0-dev.36",
26
+ "@prisma-next/psl-parser": "0.13.0-dev.36",
27
+ "@prisma-next/psl-printer": "0.13.0-dev.36",
28
+ "@prisma-next/sql-contract-psl": "0.13.0-dev.36",
29
+ "@prisma-next/test-utils": "0.13.0-dev.36",
30
+ "@prisma-next/tsconfig": "0.13.0-dev.36",
31
+ "@prisma-next/tsdown": "0.13.0-dev.36",
32
32
  "tsdown": "0.22.1",
33
33
  "typescript": "5.9.3",
34
34
  "vitest": "4.1.8"
@@ -1,12 +1,16 @@
1
1
  import { ContractValidationError } from '@prisma-next/contract/contract-validation-error';
2
+ import { isPlainRecord } from '@prisma-next/contract/is-plain-record';
2
3
  import type { Contract } from '@prisma-next/contract/types';
3
4
  import type { ContractSerializer } from '@prisma-next/framework-components/control';
4
5
  import {
6
+ type AnyEntityKindDescriptor,
7
+ hydrateNamespaceEntities,
5
8
  type Namespace,
6
9
  NamespaceBase,
7
10
  UNBOUND_NAMESPACE_ID,
8
11
  } from '@prisma-next/framework-components/ir';
9
12
  import { sqlContractCanonicalizationHooks } from '@prisma-next/sql-contract/canonicalization-hooks';
13
+ import { composeSqlEntityKinds } from '@prisma-next/sql-contract/entity-kinds';
10
14
  import {
11
15
  buildSqlNamespace,
12
16
  type SqlNamespaceTablesInput,
@@ -14,14 +18,9 @@ import {
14
18
  type SqlStorageInput,
15
19
  type SqlStorageTypeEntry,
16
20
  SqlUnboundNamespace,
17
- StorageTable,
18
- type StorageTableInput,
19
- StorageValueSet,
20
- type StorageValueSetInput,
21
21
  } from '@prisma-next/sql-contract/types';
22
22
  import {
23
23
  createSqlContractSchema,
24
- createSqlEntrySchemaRegistry,
25
24
  validateSqlContractFully,
26
25
  } from '@prisma-next/sql-contract/validators';
27
26
  import { blindCast } from '@prisma-next/utils/casts';
@@ -37,10 +36,6 @@ const NamespaceRawSchema = type({
37
36
  }),
38
37
  });
39
38
 
40
- function isPlainRecord(value: unknown): value is Record<string, unknown> {
41
- return typeof value === 'object' && value !== null && !Array.isArray(value);
42
- }
43
-
44
39
  export type SqlEntityHydrationFactory = (entry: unknown) => unknown;
45
40
 
46
41
  /**
@@ -71,23 +66,18 @@ export abstract class SqlContractSerializerBase<TContract extends Contract<SqlSt
71
66
  implements ContractSerializer<TContract>
72
67
  {
73
68
  private readonly contractSchema: Type<unknown> | undefined;
69
+ private readonly entryKinds: ReadonlyMap<string, AnyEntityKindDescriptor>;
74
70
 
75
71
  constructor(
76
72
  protected readonly entityHydrationRegistry: ReadonlyMap<
77
73
  string,
78
74
  SqlEntityHydrationFactory
79
75
  > = new Map(),
80
- validatorRegistry: ReadonlyMap<string, Type<unknown>> = new Map(),
76
+ packEntityKinds: readonly AnyEntityKindDescriptor[] = [],
81
77
  ) {
82
- // One uniform registry: SQL core's kinds and pack contributions are
83
- // composed into the same map. Only build a per-instance contract
84
- // schema when pack contributions exist — the cached module-level
85
- // default in `validators.ts` is the same composition with no pack
86
- // entries and avoids per-instance schema compilation.
78
+ this.entryKinds = composeSqlEntityKinds(packEntityKinds);
87
79
  this.contractSchema =
88
- validatorRegistry.size > 0
89
- ? createSqlContractSchema(createSqlEntrySchemaRegistry(validatorRegistry))
90
- : undefined;
80
+ packEntityKinds.length > 0 ? createSqlContractSchema(this.entryKinds) : undefined;
91
81
  }
92
82
 
93
83
  deserializeContract<T extends TContract = TContract>(json: unknown): T {
@@ -150,7 +140,7 @@ export abstract class SqlContractSerializerBase<TContract extends Contract<SqlSt
150
140
  // framework `Namespace` to the SQL-family `SqlNamespace`.
151
141
  namespaces: blindCast<
152
142
  SqlStorageInput['namespaces'],
153
- 'hydrated SQL namespaces are SqlNamespace instances (family hydration guarantees this)'
143
+ '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.'
154
144
  >({ ...hydratedNamespaces, [UNBOUND_NAMESPACE_ID]: unbound }),
155
145
  }),
156
146
  };
@@ -191,81 +181,30 @@ export abstract class SqlContractSerializerBase<TContract extends Contract<SqlSt
191
181
  const messages = parsed.map((p: { message: string }) => p.message).join('; ');
192
182
  throw new ContractValidationError(`Namespace hydration failed: ${messages}`, 'structural');
193
183
  }
194
- const entriesOutput: Record<string, Record<string, unknown>> = {};
195
184
  const entriesRaw = parsed.entries;
196
- if (entriesRaw !== undefined && typeof entriesRaw === 'object' && entriesRaw !== null) {
197
- const rawEntries = entriesRaw as Record<string, unknown>;
198
- for (const [key, innerMap] of Object.entries(rawEntries)) {
199
- const hydrated = this.hydrateEntriesKind(key, innerMap);
200
- if (hydrated === undefined) {
201
- throw new ContractValidationError(
202
- `Unknown entries key "${key}" in namespace "${id}"; no hydration factory registered for this entity kind`,
203
- 'structural',
204
- );
205
- }
206
- entriesOutput[key] = hydrated;
207
- }
185
+ const rawEntriesMap = isPlainRecord(entriesRaw) ? entriesRaw : {};
186
+
187
+ const entriesInput: Record<string, Readonly<Record<string, unknown>>> = {};
188
+ for (const [key, innerMap] of Object.entries(rawEntriesMap)) {
189
+ entriesInput[key] = isPlainRecord(innerMap) ? innerMap : Object.freeze({});
208
190
  }
191
+
192
+ const entriesOutput = hydrateNamespaceEntities(entriesInput, this.entryKinds, 'fail', id);
193
+
209
194
  // Always ensure a 'table' key is present (may be empty).
210
195
  if (!Object.hasOwn(entriesOutput, 'table')) {
211
196
  entriesOutput['table'] = {};
212
197
  }
213
198
 
214
- return blindCast<SqlNamespaceTablesInput, 'hydrated namespace entries input'>({
199
+ return blindCast<
200
+ SqlNamespaceTablesInput,
201
+ 'entriesOutput holds the hydrated SQL entity-kind maps (table always present); this wraps them as the SqlNamespaceTablesInput the family createNamespace consumes.'
202
+ >({
215
203
  id,
216
204
  entries: entriesOutput,
217
205
  });
218
206
  }
219
207
 
220
- protected hydrateEntriesKind(
221
- key: string,
222
- innerMap: unknown,
223
- ): Record<string, unknown> | undefined {
224
- if (key === 'table') {
225
- if (innerMap === null || typeof innerMap !== 'object' || Array.isArray(innerMap)) {
226
- return {};
227
- }
228
- return Object.fromEntries(
229
- Object.entries(
230
- blindCast<
231
- Record<string, unknown>,
232
- 'table inner map is a plain record after object check'
233
- >(innerMap),
234
- ).map(([tableName, table]) => [
235
- tableName,
236
- new StorageTable(
237
- blindCast<
238
- StorageTableInput,
239
- 'each table value is StorageTableInput by contract schema'
240
- >(table),
241
- ),
242
- ]),
243
- );
244
- }
245
- if (key === 'valueSet') {
246
- if (innerMap === null || typeof innerMap !== 'object' || Array.isArray(innerMap)) {
247
- return {};
248
- }
249
- return Object.fromEntries(
250
- Object.entries(
251
- blindCast<
252
- Record<string, unknown>,
253
- 'valueSet inner map is a plain record after object check'
254
- >(innerMap),
255
- ).map(([vsName, vs]) => [
256
- vsName,
257
- new StorageValueSet(
258
- blindCast<StorageValueSetInput, 'valueSet entry is StorageValueSetInput after parse'>(
259
- vs,
260
- ),
261
- ),
262
- ]),
263
- );
264
- }
265
- // Delegate unknown keys to subclass — return undefined to fail closed.
266
- return undefined;
267
- }
268
-
269
208
  protected hydrateStorageTypeEntry(entry: SqlStorageTypeEntry): SqlStorageTypeEntry {
270
209
  if (typeof entry !== 'object' || entry === null) {
271
210
  return entry;
@@ -1 +0,0 @@
1
- {"version":3,"file":"sql-contract-serializer-D6-28zKd.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 type { Contract } from '@prisma-next/contract/types';\nimport type { ContractSerializer } from '@prisma-next/framework-components/control';\nimport {\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 {\n buildSqlNamespace,\n type SqlNamespaceTablesInput,\n SqlStorage,\n type SqlStorageInput,\n type SqlStorageTypeEntry,\n SqlUnboundNamespace,\n StorageTable,\n type StorageTableInput,\n StorageValueSet,\n type StorageValueSetInput,\n} from '@prisma-next/sql-contract/types';\nimport {\n createSqlContractSchema,\n createSqlEntrySchemaRegistry,\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\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\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\n constructor(\n protected readonly entityHydrationRegistry: ReadonlyMap<\n string,\n SqlEntityHydrationFactory\n > = new Map(),\n validatorRegistry: ReadonlyMap<string, Type<unknown>> = new Map(),\n ) {\n // One uniform registry: SQL core's kinds and pack contributions are\n // composed into the same map. Only build a per-instance contract\n // schema when pack contributions exist — the cached module-level\n // default in `validators.ts` is the same composition with no pack\n // entries and avoids per-instance schema compilation.\n this.contractSchema =\n validatorRegistry.size > 0\n ? createSqlContractSchema(createSqlEntrySchemaRegistry(validatorRegistry))\n : 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 const unbound = hydratedNamespaces[UNBOUND_NAMESPACE_ID] ?? SqlUnboundNamespace.instance;\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 'hydrated SQL namespaces are SqlNamespace instances (family hydration guarantees this)'\n >({ ...hydratedNamespaces, [UNBOUND_NAMESPACE_ID]: unbound }),\n }),\n };\n }\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 entriesOutput: Record<string, Record<string, unknown>> = {};\n const entriesRaw = parsed.entries;\n if (entriesRaw !== undefined && typeof entriesRaw === 'object' && entriesRaw !== null) {\n const rawEntries = entriesRaw as Record<string, unknown>;\n for (const [key, innerMap] of Object.entries(rawEntries)) {\n const hydrated = this.hydrateEntriesKind(key, innerMap);\n if (hydrated === undefined) {\n throw new ContractValidationError(\n `Unknown entries key \"${key}\" in namespace \"${id}\"; no hydration factory registered for this entity kind`,\n 'structural',\n );\n }\n entriesOutput[key] = hydrated;\n }\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<SqlNamespaceTablesInput, 'hydrated namespace entries input'>({\n id,\n entries: entriesOutput,\n });\n }\n\n protected hydrateEntriesKind(\n key: string,\n innerMap: unknown,\n ): Record<string, unknown> | undefined {\n if (key === 'table') {\n if (innerMap === null || typeof innerMap !== 'object' || Array.isArray(innerMap)) {\n return {};\n }\n return Object.fromEntries(\n Object.entries(\n blindCast<\n Record<string, unknown>,\n 'table inner map is a plain record after object check'\n >(innerMap),\n ).map(([tableName, table]) => [\n tableName,\n new StorageTable(\n blindCast<\n StorageTableInput,\n 'each table value is StorageTableInput by contract schema'\n >(table),\n ),\n ]),\n );\n }\n if (key === 'valueSet') {\n if (innerMap === null || typeof innerMap !== 'object' || Array.isArray(innerMap)) {\n return {};\n }\n return Object.fromEntries(\n Object.entries(\n blindCast<\n Record<string, unknown>,\n 'valueSet inner map is a plain record after object check'\n >(innerMap),\n ).map(([vsName, vs]) => [\n vsName,\n new StorageValueSet(\n blindCast<StorageValueSetInput, 'valueSet entry is StorageValueSetInput after parse'>(\n vs,\n ),\n ),\n ]),\n );\n }\n // Delegate unknown keys to subclass — return undefined to fail closed.\n return undefined;\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 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"],"mappings":"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"}