@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 +1 -1
- package/dist/ir.d.mts +3 -4
- package/dist/ir.d.mts.map +1 -1
- package/dist/ir.mjs +1 -1
- package/dist/{sql-contract-serializer-D6-28zKd.mjs → sql-contract-serializer-BKSX9JhA.mjs} +14 -28
- package/dist/sql-contract-serializer-BKSX9JhA.mjs.map +1 -0
- package/package.json +21 -21
- package/src/core/ir/sql-contract-serializer-base.ts +21 -82
- package/dist/sql-contract-serializer-D6-28zKd.mjs.map +0 -1
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-
|
|
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
|
-
|
|
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":"
|
|
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-
|
|
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 {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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
|
-
|
|
44
|
+
entryKinds;
|
|
45
|
+
constructor(entityHydrationRegistry = /* @__PURE__ */ new Map(), packEntityKinds = []) {
|
|
46
46
|
this.entityHydrationRegistry = entityHydrationRegistry;
|
|
47
|
-
this.
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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-
|
|
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":";;;;;;;;;;;AA8BA,MAAM,qBAAqB,KAAK;CAC9B,IAAI;CACJ,SAAS;CACT,SAAS,KAAK,EACZ,KAAK,SACP,CAAC;AACH,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA4BD,IAAsB,4BAAtB,MAEA;CAKuB;CAJrB;CACA;CAEA,YACE,0CAGI,IAAI,IAAI,GACZ,kBAAsD,CAAC,GACvD;EALmB,KAAA,0BAAA;EAMnB,KAAK,aAAa,sBAAsB,eAAe;EACvD,KAAK,iBACH,gBAAgB,SAAS,IAAI,wBAAwB,KAAK,UAAU,IAAI,KAAA;CAC5E;CAEA,oBAAqD,MAAkB;EACrE,MAAM,YAAY,KAAK,0BAA0B,IAAI;EACrD,MAAM,WAAW,KAAK,kBAAkB,SAAS;EACjD,OAAO,KAAK,wBAAwB,QAAQ;CAC9C;CAEA,kBAAkB,UAAiC;EACjD,OAAO;CACT;CAEA,sBAAsB,iCAAiC;CAEvD,cAAc,iCAAiC;CAE/C,0BAAoC,MAAqC;EACvE,OAAO,yBACL,MACA,KAAK,mBAAmB,KAAA,IAAY,EAAE,gBAAgB,KAAK,eAAe,IAAI,KAAA,CAChF;CACF;CAEA,kBAA4B,WAAuD;EACjF,MAAM,QAAQ,UAAU,QAAQ;EAChC,MAAM,gBACJ,UAAU,KAAA,IACN,OAAO,YACL,OAAO,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW,CAC3C,MACA,KAAK,wBAAwB,KAAK,CACpC,CAAC,CACH,IACA,KAAA;EAEN,MAAM,gBAAgB,UAAU,QAAQ;EACxC,IAAI,kBAAkB,KAAA,GACpB,MAAM,IAAI,wBACR,uEACA,YACF;EAEF,MAAM,qBAAqB,KAAK,uBAAuB,aAAa;EASpE,MAAM,UAAU,mBAAmB,yBAAyB,oBAAoB;EAEhF,OAAO;GACL,GAAG;GACH,SAAS,IAAI,WAAW;IACtB,aAAa,UAAU,QAAQ;IAC/B,GAAG,UAAU,SAAS,aAAa;IAGnC,YAAY,UAGV;KAAE,GAAG;MAAqB,uBAAuB;IAAQ,CAAC;GAC9D,CAAC;EACH;CACF;CAEA,uBACE,YACqC;EACrC,OAAO,OAAO,YACZ,OAAO,QAAQ,UAAU,CAAC,CAAC,KAAK,CAAC,MAAM,uBAAuB;GAE5D,MAAM,oBAAoB,KAAK,yBAAyB,MAAM,iBAAiB;GAU/E,OAAO,CAAC,MARN,6BAA6B,gBACzB,oBACA,kBACE,UAGE,iBAAiB,CACrB,CAC6B;EACrC,CAAC,CACH;CACF;CAEA,yBACE,MACA,KACqC;EACrC,IAAI,eAAe,eACjB,OAAO;EAET,MAAM,YAAY,cAAc,GAAG,IAAI,MAAM,CAAC;EAC9C,MAAM,KAAK,OAAO,UAAU,UAAU,WAAW,UAAU,QAAQ;EACnE,MAAM,SAAS,mBAAmB;GAAE,GAAG;GAAW;EAAG,CAAC;EACtD,IAAI,kBAAkB,KAAK,QAEzB,MAAM,IAAI,wBAAwB,+BADjB,OAAO,KAAK,MAA2B,EAAE,OAAO,CAAC,CAAC,KAAK,IACA,KAAK,YAAY;EAE3F,MAAM,aAAa,OAAO;EAC1B,MAAM,gBAAgB,cAAc,UAAU,IAAI,aAAa,CAAC;EAEhE,MAAM,eAAkE,CAAC;EACzE,KAAK,MAAM,CAAC,KAAK,aAAa,OAAO,QAAQ,aAAa,GACxD,aAAa,OAAO,cAAc,QAAQ,IAAI,WAAW,OAAO,OAAO,CAAC,CAAC;EAG3E,MAAM,gBAAgB,yBAAyB,cAAc,KAAK,YAAY,QAAQ,EAAE;EAGxF,IAAI,CAAC,OAAO,OAAO,eAAe,OAAO,GACvC,cAAc,WAAW,CAAC;EAG5B,OAAO,UAGL;GACA;GACA,SAAS;EACX,CAAC;CACH;CAEA,wBAAkC,OAAiD;EACjF,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;EAET,MAAM,OAAQ,MAA6B;EAC3C,IAAI,OAAO,SAAS,UAClB,OAAO;EAET,MAAM,UAAU,KAAK,wBAAwB,IAAI,IAAI;EACrD,IAAI,YAAY,KAAA,GACd,OAAO;EAET,OAAO,UAGL,QAAQ,KAAK,CAAC;CAClB;CAEA,wBAAkC,UAA2C;EAC3E,OAAO;CACT;AACF;;;;;;;;;;;;ACvNA,IAAa,wBAAb,cAA2C,0BAAgD;CACzF,cAAc;EACZ,sBAAM,IAAI,IAAI,CAAC;CACjB;AACF"}
|
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/family-sql",
|
|
3
|
-
"version": "0.13.0-dev.
|
|
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.
|
|
10
|
-
"@prisma-next/emitter": "0.13.0-dev.
|
|
11
|
-
"@prisma-next/framework-components": "0.13.0-dev.
|
|
12
|
-
"@prisma-next/migration-tools": "0.13.0-dev.
|
|
13
|
-
"@prisma-next/operations": "0.13.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract": "0.13.0-dev.
|
|
15
|
-
"@prisma-next/sql-contract-emitter": "0.13.0-dev.
|
|
16
|
-
"@prisma-next/sql-contract-ts": "0.13.0-dev.
|
|
17
|
-
"@prisma-next/sql-operations": "0.13.0-dev.
|
|
18
|
-
"@prisma-next/sql-relational-core": "0.13.0-dev.
|
|
19
|
-
"@prisma-next/sql-runtime": "0.13.0-dev.
|
|
20
|
-
"@prisma-next/sql-schema-ir": "0.13.0-dev.
|
|
21
|
-
"@prisma-next/utils": "0.13.0-dev.
|
|
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.
|
|
26
|
-
"@prisma-next/psl-parser": "0.13.0-dev.
|
|
27
|
-
"@prisma-next/psl-printer": "0.13.0-dev.
|
|
28
|
-
"@prisma-next/sql-contract-psl": "0.13.0-dev.
|
|
29
|
-
"@prisma-next/test-utils": "0.13.0-dev.
|
|
30
|
-
"@prisma-next/tsconfig": "0.13.0-dev.
|
|
31
|
-
"@prisma-next/tsdown": "0.13.0-dev.
|
|
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
|
-
|
|
76
|
+
packEntityKinds: readonly AnyEntityKindDescriptor[] = [],
|
|
81
77
|
) {
|
|
82
|
-
|
|
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
|
-
|
|
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
|
-
'
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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<
|
|
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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"}
|