@prisma-next/family-sql 0.10.0-dev.9 → 0.11.0
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 -1
- package/dist/ir.d.mts.map +1 -1
- package/dist/ir.mjs +1 -1
- package/dist/{sql-contract-serializer-C6ypWJYR.mjs → sql-contract-serializer-COnYiewe.mjs} +47 -9
- package/dist/sql-contract-serializer-COnYiewe.mjs.map +1 -0
- package/package.json +21 -21
- package/src/core/ir/sql-contract-serializer-base.ts +94 -17
- package/dist/sql-contract-serializer-C6ypWJYR.mjs.map +0 -1
package/dist/control.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as sqlFamilyAuthoringFieldPresets, t as sqlFamilyAuthoringTypes } from "./authoring-type-constructors-F4JpCJl7.mjs";
|
|
2
|
-
import { t as SqlContractSerializer } from "./sql-contract-serializer-
|
|
2
|
+
import { t as SqlContractSerializer } from "./sql-contract-serializer-COnYiewe.mjs";
|
|
3
3
|
import { a as extractCodecControlHooks, t as verifySqlSchema } from "./verify-sql-schema-Bj4Wqe2c.mjs";
|
|
4
4
|
import { t as collectSupportedCodecTypeIds } from "./verify-Crewz6hG.mjs";
|
|
5
5
|
import { n as temporalAuthoringPresets, r as timestampNowControlDescriptor } from "./timestamp-now-generator-r7BP5n3l.mjs";
|
package/dist/ir.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ContractSerializer, SchemaIssue, SchemaVerifier, SchemaVerifyOptions, SchemaVerifyResult } from "@prisma-next/framework-components/control";
|
|
2
2
|
import { Namespace } from "@prisma-next/framework-components/ir";
|
|
3
3
|
import { SqlNamespaceTablesInput, SqlStorage, SqlStorageTypeEntry } from "@prisma-next/sql-contract/types";
|
|
4
|
+
import { Type } from "arktype";
|
|
4
5
|
import { Contract } from "@prisma-next/contract/types";
|
|
5
6
|
import { JsonObject } from "@prisma-next/utils/json";
|
|
6
7
|
|
|
@@ -32,7 +33,8 @@ type SqlEntityHydrationFactory = (entry: unknown) => SqlStorageTypeEntry;
|
|
|
32
33
|
*/
|
|
33
34
|
declare abstract class SqlContractSerializerBase<TContract extends Contract<SqlStorage>> implements ContractSerializer<TContract> {
|
|
34
35
|
private readonly entityTypeRegistry;
|
|
35
|
-
|
|
36
|
+
private readonly contractSchema;
|
|
37
|
+
constructor(entityTypeRegistry?: ReadonlyMap<string, SqlEntityHydrationFactory>, validatorFragments?: ReadonlyMap<string, Type<unknown>>);
|
|
36
38
|
deserializeContract<T extends TContract = TContract>(json: unknown): T;
|
|
37
39
|
serializeContract(contract: TContract): JsonObject;
|
|
38
40
|
protected parseSqlContractStructure(json: unknown): Contract<SqlStorage>;
|
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":";;;;;;;;KA2BY,yBAAA,IAA6B,KAAA,cAAmB,mBAAA;;AAA5D;;;;;AA0BA;;;;;;;;;;;;;;;;;;uBAAsB,yBAAA,mBAA4C,QAAA,CAAS,UAAA,cAC9D,kBAAA,CAAmB,SAAA;EAAA,iBAKX,kBAAA;EAAA,iBAHF,cAAA;cAGE,kBAAA,GAAoB,WAAA,SAAoB,yBAAA,GACzD,kBAAA,GAAqB,WAAA,SAAoB,IAAA;EAW3C,mBAAA,WAA8B,SAAA,GAAY,SAAA,CAAA,CAAW,IAAA,YAAgB,CAAA;EAMrE,iBAAA,CAAkB,QAAA,EAAU,SAAA,GAAY,UAAA;EAAA,UAI9B,yBAAA,CAA0B,IAAA,YAAgB,QAAA,CAAS,UAAA;EAAA,UAOnD,iBAAA,CAAkB,SAAA,EAAW,QAAA,CAAS,UAAA,IAAc,QAAA,CAAS,UAAA;EAAA,UA0B7D,sBAAA,CACR,UAAA,EAAY,QAAA,CAAS,MAAA,SAAe,SAAA,GAAY,MAAA,sBAC/C,QAAA,CAAS,MAAA,SAAe,SAAA,GAAY,uBAAA;EAAA,UAS7B,wBAAA,CACR,IAAA,UACA,GAAA,EAAK,SAAA,GAAY,MAAA,oBAChB,SAAA,GAAY,uBAAA;EAAA,UA6EL,uBAAA,CAAwB,KAAA,EAAO,mBAAA,GAAsB,mBAAA;EAAA,UAerD,uBAAA,CAAwB,QAAA,EAAU,QAAA,CAAS,UAAA,IAAc,SAAA;AAAA;;;;;;;;AAjMrE;;;;cCda,qBAAA,SAA8B,yBAAA,CAA0B,QAAA,CAAS,UAAA;;;;;;;;;;;;ADc9E;;;;;AA0BA;;;;;;;;uBE1BsB,qBAAA,gCACT,cAAA,CAAe,SAAA,EAAW,OAAA;EAErC,YAAA,CAAa,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,IAAW,kBAAA;EFyClC;;;;;;EAAA,mBE5BX,qBAAA,CACjB,OAAA,EAAS,mBAAA,CAAoB,SAAA,EAAW,OAAA,aAC9B,WAAA;EF2CoC;;;;;EAAA,mBEpC7B,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-COnYiewe.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
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { ContractValidationError } from "@prisma-next/contract/contract-validation-error";
|
|
2
2
|
import { NamespaceBase } from "@prisma-next/framework-components/ir";
|
|
3
3
|
import { SqlStorage, StorageTable } from "@prisma-next/sql-contract/types";
|
|
4
|
-
import { validateSqlContractFully } from "@prisma-next/sql-contract/validators";
|
|
4
|
+
import { createSqlContractSchema, validateSqlContractFully } from "@prisma-next/sql-contract/validators";
|
|
5
|
+
import { type } from "arktype";
|
|
5
6
|
//#region src/core/ir/sql-contract-serializer-base.ts
|
|
7
|
+
const NamespaceRawSchema = type({
|
|
8
|
+
id: "string",
|
|
9
|
+
"kind?": "string"
|
|
10
|
+
});
|
|
11
|
+
function isPlainRecord(value) {
|
|
12
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
6
14
|
/**
|
|
7
15
|
* SQL family `ContractSerializer` abstract base. Carries the SQL-shared
|
|
8
16
|
* deserialization pipeline:
|
|
@@ -29,8 +37,10 @@ import { validateSqlContractFully } from "@prisma-next/sql-contract/validators";
|
|
|
29
37
|
*/
|
|
30
38
|
var SqlContractSerializerBase = class {
|
|
31
39
|
entityTypeRegistry;
|
|
32
|
-
|
|
40
|
+
contractSchema;
|
|
41
|
+
constructor(entityTypeRegistry = /* @__PURE__ */ new Map(), validatorFragments) {
|
|
33
42
|
this.entityTypeRegistry = entityTypeRegistry;
|
|
43
|
+
this.contractSchema = validatorFragments !== void 0 && validatorFragments.size > 0 ? createSqlContractSchema(validatorFragments) : void 0;
|
|
34
44
|
}
|
|
35
45
|
deserializeContract(json) {
|
|
36
46
|
const validated = this.parseSqlContractStructure(json);
|
|
@@ -41,7 +51,7 @@ var SqlContractSerializerBase = class {
|
|
|
41
51
|
return contract;
|
|
42
52
|
}
|
|
43
53
|
parseSqlContractStructure(json) {
|
|
44
|
-
return validateSqlContractFully(json);
|
|
54
|
+
return validateSqlContractFully(json, this.contractSchema !== void 0 ? { contractSchema: this.contractSchema } : void 0);
|
|
45
55
|
}
|
|
46
56
|
hydrateSqlStorage(validated) {
|
|
47
57
|
const types = validated.storage.types;
|
|
@@ -62,12 +72,40 @@ var SqlContractSerializerBase = class {
|
|
|
62
72
|
}
|
|
63
73
|
hydrateSqlNamespaceEntry(nsId, raw) {
|
|
64
74
|
if (raw instanceof NamespaceBase) return raw;
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
const
|
|
75
|
+
const rawRecord = isPlainRecord(raw) ? raw : {};
|
|
76
|
+
const id = typeof rawRecord["id"] === "string" ? rawRecord["id"] : nsId;
|
|
77
|
+
const parsed = NamespaceRawSchema({
|
|
78
|
+
...rawRecord,
|
|
79
|
+
id
|
|
80
|
+
});
|
|
81
|
+
if (parsed instanceof type.errors) throw new ContractValidationError(`Namespace hydration failed: ${parsed.map((p) => p.message).join("; ")}`, "structural");
|
|
82
|
+
const result = { id };
|
|
83
|
+
for (const [propertyKey, slotValue] of Object.entries(parsed)) {
|
|
84
|
+
if (propertyKey === "id") continue;
|
|
85
|
+
if (slotValue === null || typeof slotValue !== "object") continue;
|
|
86
|
+
if (propertyKey === "tables") {
|
|
87
|
+
result["tables"] = Object.fromEntries(Object.entries(slotValue).map(([tableName, table]) => [tableName, table instanceof StorageTable ? table : new StorageTable(table)]));
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const hydratedSlot = Object.fromEntries(Object.entries(slotValue).map(([entryName, entry]) => {
|
|
91
|
+
if (typeof entry !== "object" || entry === null) return [entryName, entry];
|
|
92
|
+
const kind = entry.kind;
|
|
93
|
+
if (typeof kind === "string") {
|
|
94
|
+
const factory = this.entityTypeRegistry.get(kind);
|
|
95
|
+
if (factory !== void 0) return [entryName, factory(entry)];
|
|
96
|
+
}
|
|
97
|
+
return [entryName, entry];
|
|
98
|
+
}));
|
|
99
|
+
if (Object.keys(hydratedSlot).length > 0) result[propertyKey] = hydratedSlot;
|
|
100
|
+
}
|
|
101
|
+
const typesRaw = rawRecord["types"];
|
|
102
|
+
if (typesRaw !== void 0 && typeof typesRaw === "object" && typesRaw !== null && Object.values(typesRaw).some((entry) => typeof entry === "object" && entry !== null && entry.kind === "postgres-enum") && this.entityTypeRegistry.get("postgres-enum") === void 0) throw new ContractValidationError("Per-schema database types (e.g. postgres-enum) under storage.namespaces[..].types require PostgresContractSerializer.", "structural");
|
|
103
|
+
const tables = result["tables"] ?? {};
|
|
104
|
+
const types = result["types"];
|
|
68
105
|
return {
|
|
69
|
-
id
|
|
70
|
-
tables
|
|
106
|
+
id,
|
|
107
|
+
tables,
|
|
108
|
+
...types !== void 0 ? { types } : {}
|
|
71
109
|
};
|
|
72
110
|
}
|
|
73
111
|
hydrateStorageTypeEntry(entry) {
|
|
@@ -101,4 +139,4 @@ var SqlContractSerializer = class extends SqlContractSerializerBase {
|
|
|
101
139
|
//#endregion
|
|
102
140
|
export { SqlContractSerializerBase as n, SqlContractSerializer as t };
|
|
103
141
|
|
|
104
|
-
//# sourceMappingURL=sql-contract-serializer-
|
|
142
|
+
//# sourceMappingURL=sql-contract-serializer-COnYiewe.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-contract-serializer-COnYiewe.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 { type Namespace, NamespaceBase } from '@prisma-next/framework-components/ir';\nimport {\n type SqlNamespaceTablesInput,\n SqlStorage,\n type SqlStorageTypeEntry,\n StorageTable,\n type StorageTableInput,\n} from '@prisma-next/sql-contract/types';\nimport {\n createSqlContractSchema,\n validateSqlContractFully,\n} from '@prisma-next/sql-contract/validators';\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});\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) => SqlStorageTypeEntry;\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 private readonly entityTypeRegistry: ReadonlyMap<string, SqlEntityHydrationFactory> = new Map(),\n validatorFragments?: ReadonlyMap<string, Type<unknown>>,\n ) {\n // Only build a fragments-aware contract schema when pack contributions\n // exist. The cached module-level default in `validators.ts` covers the\n // no-contributions case and avoids per-instance schema compilation.\n this.contractSchema =\n validatorFragments !== undefined && validatorFragments.size > 0\n ? createSqlContractSchema(validatorFragments)\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 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 const hydratedNamespaces =\n rawNamespaces !== undefined ? this.hydrateSqlNamespaceMap(rawNamespaces) : undefined;\n\n return {\n ...validated,\n storage: new SqlStorage({\n storageHash: validated.storage.storageHash,\n ...(hydratedTypes !== undefined ? { types: hydratedTypes } : {}),\n ...(hydratedNamespaces !== undefined ? { namespaces: hydratedNamespaces } : {}),\n }),\n };\n }\n\n protected hydrateSqlNamespaceMap(\n namespaces: Readonly<Record<string, Namespace | Record<string, unknown>>>,\n ): Readonly<Record<string, Namespace | SqlNamespaceTablesInput>> {\n return Object.fromEntries(\n Object.entries(namespaces).map(([nsId, raw]) => [\n nsId,\n this.hydrateSqlNamespaceEntry(nsId, raw),\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 result: Record<string, unknown> = { id };\n\n for (const [propertyKey, slotValue] of Object.entries(parsed)) {\n if (propertyKey === 'id') continue;\n if (slotValue === null || typeof slotValue !== 'object') continue;\n\n if (propertyKey === 'tables') {\n result['tables'] = Object.fromEntries(\n Object.entries(slotValue as Record<string, unknown>).map(([tableName, table]) => [\n tableName,\n table instanceof StorageTable ? table : new StorageTable(table as StorageTableInput),\n ]),\n );\n continue;\n }\n\n const hydratedSlot = Object.fromEntries(\n Object.entries(slotValue as Record<string, unknown>).map(([entryName, entry]) => {\n if (typeof entry !== 'object' || entry === null) {\n return [entryName, entry];\n }\n const kind = (entry as { kind?: unknown }).kind;\n if (typeof kind === 'string') {\n const factory = this.entityTypeRegistry.get(kind);\n if (factory !== undefined) {\n return [entryName, factory(entry)];\n }\n }\n return [entryName, entry];\n }),\n );\n if (Object.keys(hydratedSlot).length > 0) {\n result[propertyKey] = hydratedSlot;\n }\n }\n\n const typesRaw = rawRecord['types'];\n const hasUnhydratedPostgresEnumEntry =\n typesRaw !== undefined &&\n typeof typesRaw === 'object' &&\n typesRaw !== null &&\n Object.values(typesRaw as Record<string, unknown>).some(\n (entry) =>\n typeof entry === 'object' &&\n entry !== null &&\n (entry as { kind?: unknown }).kind === 'postgres-enum',\n );\n if (\n hasUnhydratedPostgresEnumEntry &&\n this.entityTypeRegistry.get('postgres-enum') === undefined\n ) {\n throw new ContractValidationError(\n 'Per-schema database types (e.g. postgres-enum) under storage.namespaces[..].types require PostgresContractSerializer.',\n 'structural',\n );\n }\n\n const tables = (result['tables'] ?? {}) as Record<string, StorageTable>;\n const types = result['types'] as NonNullable<SqlNamespaceTablesInput['types']> | undefined;\n return {\n id,\n tables,\n ...(types !== undefined ? { types } : {}),\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.entityTypeRegistry.get(kind);\n if (factory === undefined) {\n return entry;\n }\n return 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.
|
|
3
|
+
"version": "0.11.0",
|
|
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.
|
|
10
|
-
"@prisma-next/emitter": "0.
|
|
11
|
-
"@prisma-next/framework-components": "0.
|
|
12
|
-
"@prisma-next/migration-tools": "0.
|
|
13
|
-
"@prisma-next/operations": "0.
|
|
14
|
-
"@prisma-next/sql-contract": "0.
|
|
15
|
-
"@prisma-next/sql-contract-emitter": "0.
|
|
16
|
-
"@prisma-next/sql-contract-ts": "0.
|
|
17
|
-
"@prisma-next/sql-operations": "0.
|
|
18
|
-
"@prisma-next/sql-relational-core": "0.
|
|
19
|
-
"@prisma-next/sql-runtime": "0.
|
|
20
|
-
"@prisma-next/sql-schema-ir": "0.
|
|
21
|
-
"@prisma-next/utils": "0.
|
|
9
|
+
"@prisma-next/contract": "0.11.0",
|
|
10
|
+
"@prisma-next/emitter": "0.11.0",
|
|
11
|
+
"@prisma-next/framework-components": "0.11.0",
|
|
12
|
+
"@prisma-next/migration-tools": "0.11.0",
|
|
13
|
+
"@prisma-next/operations": "0.11.0",
|
|
14
|
+
"@prisma-next/sql-contract": "0.11.0",
|
|
15
|
+
"@prisma-next/sql-contract-emitter": "0.11.0",
|
|
16
|
+
"@prisma-next/sql-contract-ts": "0.11.0",
|
|
17
|
+
"@prisma-next/sql-operations": "0.11.0",
|
|
18
|
+
"@prisma-next/sql-relational-core": "0.11.0",
|
|
19
|
+
"@prisma-next/sql-runtime": "0.11.0",
|
|
20
|
+
"@prisma-next/sql-schema-ir": "0.11.0",
|
|
21
|
+
"@prisma-next/utils": "0.11.0",
|
|
22
22
|
"arktype": "^2.2.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@prisma-next/driver-postgres": "0.
|
|
26
|
-
"@prisma-next/psl-parser": "0.
|
|
27
|
-
"@prisma-next/psl-printer": "0.
|
|
28
|
-
"@prisma-next/sql-contract-psl": "0.
|
|
29
|
-
"@prisma-next/test-utils": "0.
|
|
30
|
-
"@prisma-next/tsconfig": "0.
|
|
31
|
-
"@prisma-next/tsdown": "0.
|
|
25
|
+
"@prisma-next/driver-postgres": "0.11.0",
|
|
26
|
+
"@prisma-next/psl-parser": "0.11.0",
|
|
27
|
+
"@prisma-next/psl-printer": "0.11.0",
|
|
28
|
+
"@prisma-next/sql-contract-psl": "0.11.0",
|
|
29
|
+
"@prisma-next/test-utils": "0.11.0",
|
|
30
|
+
"@prisma-next/tsconfig": "0.11.0",
|
|
31
|
+
"@prisma-next/tsdown": "0.11.0",
|
|
32
32
|
"tsdown": "0.22.0",
|
|
33
33
|
"typescript": "5.9.3",
|
|
34
34
|
"vitest": "4.1.6"
|
|
@@ -9,8 +9,21 @@ import {
|
|
|
9
9
|
StorageTable,
|
|
10
10
|
type StorageTableInput,
|
|
11
11
|
} from '@prisma-next/sql-contract/types';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
createSqlContractSchema,
|
|
14
|
+
validateSqlContractFully,
|
|
15
|
+
} from '@prisma-next/sql-contract/validators';
|
|
13
16
|
import type { JsonObject } from '@prisma-next/utils/json';
|
|
17
|
+
import { type Type, type } from 'arktype';
|
|
18
|
+
|
|
19
|
+
const NamespaceRawSchema = type({
|
|
20
|
+
id: 'string',
|
|
21
|
+
'kind?': 'string',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
25
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
14
27
|
|
|
15
28
|
export type SqlEntityHydrationFactory = (entry: unknown) => SqlStorageTypeEntry;
|
|
16
29
|
|
|
@@ -41,9 +54,20 @@ export type SqlEntityHydrationFactory = (entry: unknown) => SqlStorageTypeEntry;
|
|
|
41
54
|
export abstract class SqlContractSerializerBase<TContract extends Contract<SqlStorage>>
|
|
42
55
|
implements ContractSerializer<TContract>
|
|
43
56
|
{
|
|
57
|
+
private readonly contractSchema: Type<unknown> | undefined;
|
|
58
|
+
|
|
44
59
|
constructor(
|
|
45
|
-
private readonly entityTypeRegistry: ReadonlyMap<string, SqlEntityHydrationFactory
|
|
46
|
-
|
|
60
|
+
private readonly entityTypeRegistry: ReadonlyMap<string, SqlEntityHydrationFactory> = new Map(),
|
|
61
|
+
validatorFragments?: ReadonlyMap<string, Type<unknown>>,
|
|
62
|
+
) {
|
|
63
|
+
// Only build a fragments-aware contract schema when pack contributions
|
|
64
|
+
// exist. The cached module-level default in `validators.ts` covers the
|
|
65
|
+
// no-contributions case and avoids per-instance schema compilation.
|
|
66
|
+
this.contractSchema =
|
|
67
|
+
validatorFragments !== undefined && validatorFragments.size > 0
|
|
68
|
+
? createSqlContractSchema(validatorFragments)
|
|
69
|
+
: undefined;
|
|
70
|
+
}
|
|
47
71
|
|
|
48
72
|
deserializeContract<T extends TContract = TContract>(json: unknown): T {
|
|
49
73
|
const validated = this.parseSqlContractStructure(json);
|
|
@@ -56,7 +80,10 @@ export abstract class SqlContractSerializerBase<TContract extends Contract<SqlSt
|
|
|
56
80
|
}
|
|
57
81
|
|
|
58
82
|
protected parseSqlContractStructure(json: unknown): Contract<SqlStorage> {
|
|
59
|
-
return validateSqlContractFully<Contract<SqlStorage>>(
|
|
83
|
+
return validateSqlContractFully<Contract<SqlStorage>>(
|
|
84
|
+
json,
|
|
85
|
+
this.contractSchema !== undefined ? { contractSchema: this.contractSchema } : undefined,
|
|
86
|
+
);
|
|
60
87
|
}
|
|
61
88
|
|
|
62
89
|
protected hydrateSqlStorage(validated: Contract<SqlStorage>): Contract<SqlStorage> {
|
|
@@ -103,26 +130,76 @@ export abstract class SqlContractSerializerBase<TContract extends Contract<SqlSt
|
|
|
103
130
|
if (raw instanceof NamespaceBase) {
|
|
104
131
|
return raw;
|
|
105
132
|
}
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
133
|
+
const rawRecord = isPlainRecord(raw) ? raw : {};
|
|
134
|
+
const id = typeof rawRecord['id'] === 'string' ? rawRecord['id'] : nsId;
|
|
135
|
+
const parsed = NamespaceRawSchema({ ...rawRecord, id });
|
|
136
|
+
if (parsed instanceof type.errors) {
|
|
137
|
+
const messages = parsed.map((p: { message: string }) => p.message).join('; ');
|
|
138
|
+
throw new ContractValidationError(`Namespace hydration failed: ${messages}`, 'structural');
|
|
139
|
+
}
|
|
140
|
+
const result: Record<string, unknown> = { id };
|
|
141
|
+
|
|
142
|
+
for (const [propertyKey, slotValue] of Object.entries(parsed)) {
|
|
143
|
+
if (propertyKey === 'id') continue;
|
|
144
|
+
if (slotValue === null || typeof slotValue !== 'object') continue;
|
|
145
|
+
|
|
146
|
+
if (propertyKey === 'tables') {
|
|
147
|
+
result['tables'] = Object.fromEntries(
|
|
148
|
+
Object.entries(slotValue as Record<string, unknown>).map(([tableName, table]) => [
|
|
149
|
+
tableName,
|
|
150
|
+
table instanceof StorageTable ? table : new StorageTable(table as StorageTableInput),
|
|
151
|
+
]),
|
|
152
|
+
);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const hydratedSlot = Object.fromEntries(
|
|
157
|
+
Object.entries(slotValue as Record<string, unknown>).map(([entryName, entry]) => {
|
|
158
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
159
|
+
return [entryName, entry];
|
|
160
|
+
}
|
|
161
|
+
const kind = (entry as { kind?: unknown }).kind;
|
|
162
|
+
if (typeof kind === 'string') {
|
|
163
|
+
const factory = this.entityTypeRegistry.get(kind);
|
|
164
|
+
if (factory !== undefined) {
|
|
165
|
+
return [entryName, factory(entry)];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return [entryName, entry];
|
|
169
|
+
}),
|
|
170
|
+
);
|
|
171
|
+
if (Object.keys(hydratedSlot).length > 0) {
|
|
172
|
+
result[propertyKey] = hydratedSlot;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const typesRaw = rawRecord['types'];
|
|
177
|
+
const hasUnhydratedPostgresEnumEntry =
|
|
178
|
+
typesRaw !== undefined &&
|
|
179
|
+
typeof typesRaw === 'object' &&
|
|
180
|
+
typesRaw !== null &&
|
|
181
|
+
Object.values(typesRaw as Record<string, unknown>).some(
|
|
182
|
+
(entry) =>
|
|
183
|
+
typeof entry === 'object' &&
|
|
184
|
+
entry !== null &&
|
|
185
|
+
(entry as { kind?: unknown }).kind === 'postgres-enum',
|
|
186
|
+
);
|
|
187
|
+
if (
|
|
188
|
+
hasUnhydratedPostgresEnumEntry &&
|
|
189
|
+
this.entityTypeRegistry.get('postgres-enum') === undefined
|
|
190
|
+
) {
|
|
112
191
|
throw new ContractValidationError(
|
|
113
192
|
'Per-schema database types (e.g. postgres-enum) under storage.namespaces[..].types require PostgresContractSerializer.',
|
|
114
193
|
'structural',
|
|
115
194
|
);
|
|
116
195
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
table instanceof StorageTable ? table : new StorageTable(table as StorageTableInput),
|
|
121
|
-
]),
|
|
122
|
-
);
|
|
196
|
+
|
|
197
|
+
const tables = (result['tables'] ?? {}) as Record<string, StorageTable>;
|
|
198
|
+
const types = result['types'] as NonNullable<SqlNamespaceTablesInput['types']> | undefined;
|
|
123
199
|
return {
|
|
124
|
-
id
|
|
200
|
+
id,
|
|
125
201
|
tables,
|
|
202
|
+
...(types !== undefined ? { types } : {}),
|
|
126
203
|
};
|
|
127
204
|
}
|
|
128
205
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sql-contract-serializer-C6ypWJYR.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 { type Namespace, NamespaceBase } from '@prisma-next/framework-components/ir';\nimport {\n type SqlNamespaceTablesInput,\n SqlStorage,\n type SqlStorageTypeEntry,\n StorageTable,\n type StorageTableInput,\n} from '@prisma-next/sql-contract/types';\nimport { validateSqlContractFully } from '@prisma-next/sql-contract/validators';\nimport type { JsonObject } from '@prisma-next/utils/json';\n\nexport type SqlEntityHydrationFactory = (entry: unknown) => SqlStorageTypeEntry;\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 constructor(\n private readonly entityTypeRegistry: ReadonlyMap<string, SqlEntityHydrationFactory>,\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 protected parseSqlContractStructure(json: unknown): Contract<SqlStorage> {\n return validateSqlContractFully<Contract<SqlStorage>>(json);\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 const hydratedNamespaces =\n rawNamespaces !== undefined ? this.hydrateSqlNamespaceMap(rawNamespaces) : undefined;\n\n return {\n ...validated,\n storage: new SqlStorage({\n storageHash: validated.storage.storageHash,\n ...(hydratedTypes !== undefined ? { types: hydratedTypes } : {}),\n ...(hydratedNamespaces !== undefined ? { namespaces: hydratedNamespaces } : {}),\n }),\n };\n }\n\n protected hydrateSqlNamespaceMap(\n namespaces: Readonly<Record<string, Namespace | Record<string, unknown>>>,\n ): Readonly<Record<string, Namespace | SqlNamespaceTablesInput>> {\n return Object.fromEntries(\n Object.entries(namespaces).map(([nsId, raw]) => [\n nsId,\n this.hydrateSqlNamespaceEntry(nsId, raw),\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 obj = raw as {\n id?: string;\n tables?: Record<string, unknown>;\n types?: Record<string, unknown>;\n };\n if (obj.types !== undefined && Object.keys(obj.types).length > 0) {\n throw new ContractValidationError(\n 'Per-schema database types (e.g. postgres-enum) under storage.namespaces[..].types require PostgresContractSerializer.',\n 'structural',\n );\n }\n const tables = Object.fromEntries(\n Object.entries(obj.tables ?? {}).map(([tableName, table]) => [\n tableName,\n table instanceof StorageTable ? table : new StorageTable(table as StorageTableInput),\n ]),\n );\n return {\n id: obj.id ?? nsId,\n tables,\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.entityTypeRegistry.get(kind);\n if (factory === undefined) {\n return entry;\n }\n return 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,IAAsB,4BAAtB,MAEA;CAEqB;CADnB,YACE,oBACA;EADiB,KAAA,qBAAA;;CAGnB,oBAAqD,MAAkB;EACrE,MAAM,YAAY,KAAK,0BAA0B,KAAK;EACtD,MAAM,WAAW,KAAK,kBAAkB,UAAU;EAClD,OAAO,KAAK,wBAAwB,SAAS;;CAG/C,kBAAkB,UAAiC;EACjD,OAAO;;CAGT,0BAAoC,MAAqC;EACvE,OAAO,yBAA+C,KAAK;;CAG7D,kBAA4B,WAAuD;EACjF,MAAM,QAAQ,UAAU,QAAQ;EAChC,MAAM,gBACJ,UAAU,KAAA,IACN,OAAO,YACL,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,MAAM,WAAW,CAC3C,MACA,KAAK,wBAAwB,MAAM,CACpC,CAAC,CACH,GACD,KAAA;EAEN,MAAM,gBAAgB,UAAU,QAAQ;EACxC,MAAM,qBACJ,kBAAkB,KAAA,IAAY,KAAK,uBAAuB,cAAc,GAAG,KAAA;EAE7E,OAAO;GACL,GAAG;GACH,SAAS,IAAI,WAAW;IACtB,aAAa,UAAU,QAAQ;IAC/B,GAAI,kBAAkB,KAAA,IAAY,EAAE,OAAO,eAAe,GAAG,EAAE;IAC/D,GAAI,uBAAuB,KAAA,IAAY,EAAE,YAAY,oBAAoB,GAAG,EAAE;IAC/E,CAAC;GACH;;CAGH,uBACE,YAC+D;EAC/D,OAAO,OAAO,YACZ,OAAO,QAAQ,WAAW,CAAC,KAAK,CAAC,MAAM,SAAS,CAC9C,MACA,KAAK,yBAAyB,MAAM,IAAI,CACzC,CAAC,CACH;;CAGH,yBACE,MACA,KACqC;EACrC,IAAI,eAAe,eACjB,OAAO;EAET,MAAM,MAAM;EAKZ,IAAI,IAAI,UAAU,KAAA,KAAa,OAAO,KAAK,IAAI,MAAM,CAAC,SAAS,GAC7D,MAAM,IAAI,wBACR,yHACA,aACD;EAEH,MAAM,SAAS,OAAO,YACpB,OAAO,QAAQ,IAAI,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,WAAW,CAC3D,WACA,iBAAiB,eAAe,QAAQ,IAAI,aAAa,MAA2B,CACrF,CAAC,CACH;EACD,OAAO;GACL,IAAI,IAAI,MAAM;GACd;GACD;;CAGH,wBAAkC,OAAiD;EACjF,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;EAET,MAAM,OAAQ,MAA6B;EAC3C,IAAI,OAAO,SAAS,UAClB,OAAO;EAET,MAAM,UAAU,KAAK,mBAAmB,IAAI,KAAK;EACjD,IAAI,YAAY,KAAA,GACd,OAAO;EAET,OAAO,QAAQ,MAAM;;CAGvB,wBAAkC,UAA2C;EAC3E,OAAO;;;;;;;;;;;;;;ACnIX,IAAa,wBAAb,cAA2C,0BAAgD;CACzF,cAAc;EACZ,sBAAM,IAAI,KAAK,CAAC"}
|