@prisma-next/sql-contract 0.8.0 → 0.9.0-dev.1
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/README.md +13 -11
- package/dist/factories.d.mts +2 -2
- package/dist/factories.d.mts.map +1 -1
- package/dist/factories.mjs +16 -14
- package/dist/factories.mjs.map +1 -1
- package/dist/index-type-validation.d.mts +2 -2
- package/dist/index-type-validation.mjs +1 -1
- package/dist/index-type-validation.mjs.map +1 -1
- package/dist/{index-types-DqVqGHwg.d.mts → index-types-B1cf5N0F.d.mts} +1 -1
- package/dist/{index-types-DqVqGHwg.d.mts.map → index-types-B1cf5N0F.d.mts.map} +1 -1
- package/dist/index-types.d.mts +1 -1
- package/dist/types-B0lbr9cb.d.mts +498 -0
- package/dist/types-B0lbr9cb.d.mts.map +1 -0
- package/dist/types-iqFGDcJp.mjs +389 -0
- package/dist/types-iqFGDcJp.mjs.map +1 -0
- package/dist/types.d.mts +2 -2
- package/dist/types.mjs +2 -2
- package/dist/validators.d.mts +27 -15
- package/dist/validators.d.mts.map +1 -1
- package/dist/validators.mjs +409 -2
- package/dist/validators.mjs.map +1 -0
- package/package.json +6 -7
- package/src/exports/types.ts +30 -9
- package/src/factories.ts +19 -32
- package/src/index-type-validation.ts +1 -1
- package/src/index.ts +0 -1
- package/src/ir/foreign-key-references.ts +26 -0
- package/src/ir/foreign-key.ts +50 -0
- package/src/ir/postgres-enum-storage-entry.ts +55 -0
- package/src/ir/primary-key.ts +22 -0
- package/src/ir/sql-index.ts +33 -0
- package/src/ir/sql-node.ts +52 -0
- package/src/ir/sql-storage.ts +154 -0
- package/src/ir/sql-unspecified-namespace.ts +51 -0
- package/src/ir/storage-column.ts +55 -0
- package/src/ir/storage-table.ts +63 -0
- package/src/ir/storage-type-instance.ts +60 -0
- package/src/ir/unique-constraint.ts +22 -0
- package/src/types.ts +38 -99
- package/src/validators.ts +268 -28
- package/dist/types-hgzy8ME1.mjs +0 -13
- package/dist/types-hgzy8ME1.mjs.map +0 -1
- package/dist/types-njsiV-Ck.d.mts +0 -186
- package/dist/types-njsiV-Ck.d.mts.map +0 -1
- package/dist/validate.d.mts +0 -9
- package/dist/validate.d.mts.map +0 -1
- package/dist/validate.mjs +0 -106
- package/dist/validate.mjs.map +0 -1
- package/dist/validators-Dm5X-Hvg.mjs +0 -294
- package/dist/validators-Dm5X-Hvg.mjs.map +0 -1
- package/src/exports/validate.ts +0 -1
- package/src/validate.ts +0 -227
package/dist/validators.mjs
CHANGED
|
@@ -1,2 +1,409 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { i as SqlStorage } from "./types-iqFGDcJp.mjs";
|
|
2
|
+
import { ContractValidationError } from "@prisma-next/contract/contract-validation-error";
|
|
3
|
+
import { validateContractDomain } from "@prisma-next/contract/validate-domain";
|
|
4
|
+
import { type } from "arktype";
|
|
5
|
+
//#region src/validators.ts
|
|
6
|
+
const literalKindSchema = type("'literal'");
|
|
7
|
+
const functionKindSchema = type("'function'");
|
|
8
|
+
const generatorKindSchema = type("'generator'");
|
|
9
|
+
const generatorIdSchema = type("string").narrow((value, ctx) => {
|
|
10
|
+
return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value) ? true : ctx.mustBe("a flat generator id");
|
|
11
|
+
});
|
|
12
|
+
const ColumnDefaultLiteralSchema = type.declare().type({
|
|
13
|
+
kind: literalKindSchema,
|
|
14
|
+
value: "string | number | boolean | null | unknown[] | Record<string, unknown>"
|
|
15
|
+
});
|
|
16
|
+
const ColumnDefaultFunctionSchema = type.declare().type({
|
|
17
|
+
kind: functionKindSchema,
|
|
18
|
+
expression: "string"
|
|
19
|
+
});
|
|
20
|
+
const ColumnDefaultSchema = ColumnDefaultLiteralSchema.or(ColumnDefaultFunctionSchema);
|
|
21
|
+
const ExecutionMutationDefaultValueSchema = type({
|
|
22
|
+
"+": "reject",
|
|
23
|
+
kind: generatorKindSchema,
|
|
24
|
+
id: generatorIdSchema,
|
|
25
|
+
"params?": "Record<string, unknown>"
|
|
26
|
+
});
|
|
27
|
+
const ExecutionSchema = type({
|
|
28
|
+
"+": "reject",
|
|
29
|
+
executionHash: "string",
|
|
30
|
+
mutations: {
|
|
31
|
+
"+": "reject",
|
|
32
|
+
defaults: type({
|
|
33
|
+
"+": "reject",
|
|
34
|
+
ref: {
|
|
35
|
+
"+": "reject",
|
|
36
|
+
table: "string",
|
|
37
|
+
column: "string"
|
|
38
|
+
},
|
|
39
|
+
"onCreate?": ExecutionMutationDefaultValueSchema,
|
|
40
|
+
"onUpdate?": ExecutionMutationDefaultValueSchema
|
|
41
|
+
}).array().readonly()
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const StorageColumnSchema = type({
|
|
45
|
+
"+": "reject",
|
|
46
|
+
nativeType: "string",
|
|
47
|
+
codecId: "string",
|
|
48
|
+
nullable: "boolean",
|
|
49
|
+
"typeParams?": "Record<string, unknown>",
|
|
50
|
+
"typeRef?": "string",
|
|
51
|
+
"default?": ColumnDefaultSchema
|
|
52
|
+
}).narrow((col, ctx) => {
|
|
53
|
+
if (col.typeParams !== void 0 && col.typeRef !== void 0) return ctx.mustBe("a column with either typeParams or typeRef, not both");
|
|
54
|
+
return true;
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* Codec-triple entry persisted under `storage.types[name]`. Carries an
|
|
58
|
+
* enumerable literal `kind: 'codec-instance'` discriminator so the
|
|
59
|
+
* polymorphic slot dispatch can distinguish codec triples from
|
|
60
|
+
* class-instance kinds (e.g. `'postgres-enum'`) sharing the slot.
|
|
61
|
+
*/
|
|
62
|
+
const StorageTypeInstanceSchema = type.declare().type({
|
|
63
|
+
kind: "'codec-instance'",
|
|
64
|
+
codecId: "string",
|
|
65
|
+
nativeType: "string",
|
|
66
|
+
typeParams: "Record<string, unknown>"
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Family-layer arktype validation enumerates the polymorphic shapes the
|
|
70
|
+
* SQL family ships today (codec-instance + Postgres-enum). Pack-contributed
|
|
71
|
+
* entity types ship a parallel arktype schema entry here when they
|
|
72
|
+
* introduce a new persisted shape; the registry-driven hydration seam at
|
|
73
|
+
* `SqlContractSerializerBase.hydrateStorageTypeEntry` is open, but the
|
|
74
|
+
* family-layer structural validator is closed by design — extension
|
|
75
|
+
* packs cannot inject arbitrary persisted shapes through the slot
|
|
76
|
+
* without their structural shape being known at the family layer.
|
|
77
|
+
*
|
|
78
|
+
* A future refinement is to lift `StorageTypeEntrySchema` toward an
|
|
79
|
+
* `unknown` fallback and move structural diagnostics to the
|
|
80
|
+
* registry-dispatch site at hydration time, earned once a non-enum
|
|
81
|
+
* storage shape needs to flow through the slot without growing another
|
|
82
|
+
* closed union arm here first.
|
|
83
|
+
*/
|
|
84
|
+
const StorageTypeEntrySchema = type({
|
|
85
|
+
kind: "'postgres-enum'",
|
|
86
|
+
name: "string",
|
|
87
|
+
nativeType: "string",
|
|
88
|
+
values: type.string.array().readonly()
|
|
89
|
+
}).or(StorageTypeInstanceSchema);
|
|
90
|
+
const PrimaryKeySchema = type.declare().type({
|
|
91
|
+
columns: type.string.array().readonly(),
|
|
92
|
+
"name?": "string"
|
|
93
|
+
});
|
|
94
|
+
const UniqueConstraintSchema = type.declare().type({
|
|
95
|
+
columns: type.string.array().readonly(),
|
|
96
|
+
"name?": "string"
|
|
97
|
+
});
|
|
98
|
+
const IndexSchema = type({
|
|
99
|
+
columns: type.string.array().readonly(),
|
|
100
|
+
"name?": "string",
|
|
101
|
+
"type?": "string",
|
|
102
|
+
"options?": "Record<string, unknown>"
|
|
103
|
+
});
|
|
104
|
+
const ForeignKeyReferencesSchema = type.declare().type({
|
|
105
|
+
table: "string",
|
|
106
|
+
columns: type.string.array().readonly()
|
|
107
|
+
});
|
|
108
|
+
const ReferentialActionSchema = type.declare().type("'noAction' | 'restrict' | 'cascade' | 'setNull' | 'setDefault'");
|
|
109
|
+
const ForeignKeySchema = type.declare().type({
|
|
110
|
+
columns: type.string.array().readonly(),
|
|
111
|
+
references: ForeignKeyReferencesSchema,
|
|
112
|
+
"name?": "string",
|
|
113
|
+
"onDelete?": ReferentialActionSchema,
|
|
114
|
+
"onUpdate?": ReferentialActionSchema,
|
|
115
|
+
constraint: "boolean",
|
|
116
|
+
index: "boolean"
|
|
117
|
+
});
|
|
118
|
+
const StorageTableSchema = type({
|
|
119
|
+
"+": "reject",
|
|
120
|
+
columns: type({ "[string]": StorageColumnSchema }),
|
|
121
|
+
"primaryKey?": PrimaryKeySchema,
|
|
122
|
+
uniques: UniqueConstraintSchema.array().readonly(),
|
|
123
|
+
indexes: IndexSchema.array().readonly(),
|
|
124
|
+
foreignKeys: ForeignKeySchema.array().readonly()
|
|
125
|
+
});
|
|
126
|
+
/**
|
|
127
|
+
* Namespace entry under `storage.namespaces[id]`. SQL contracts honour
|
|
128
|
+
* the framework `Storage.namespaces` invariant from PR1; today every
|
|
129
|
+
* contract binds to the singleton placeholder
|
|
130
|
+
* (`SqlUnspecifiedNamespace.instance`) and the persisted shape carries
|
|
131
|
+
* just the namespace id. Per-target namespace concretions
|
|
132
|
+
* (`PostgresSchema`, `SqliteUnspecifiedDatabase`) can additively grow
|
|
133
|
+
* the persisted shape when they earn their slots.
|
|
134
|
+
*/
|
|
135
|
+
const NamespaceEntrySchema = type({ id: "string" });
|
|
136
|
+
const StorageSchema = type({
|
|
137
|
+
"+": "reject",
|
|
138
|
+
storageHash: "string",
|
|
139
|
+
tables: type({ "[string]": StorageTableSchema }),
|
|
140
|
+
"types?": type({ "[string]": StorageTypeEntrySchema }),
|
|
141
|
+
"namespaces?": type({ "[string]": NamespaceEntrySchema })
|
|
142
|
+
});
|
|
143
|
+
function isPlainRecord(value) {
|
|
144
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
145
|
+
}
|
|
146
|
+
function findDuplicateValue(values) {
|
|
147
|
+
const seen = /* @__PURE__ */ new Set();
|
|
148
|
+
for (const value of values) {
|
|
149
|
+
if (seen.has(value)) return value;
|
|
150
|
+
seen.add(value);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function isContractFieldType(value) {
|
|
154
|
+
if (!isPlainRecord(value)) return false;
|
|
155
|
+
const kind = value["kind"];
|
|
156
|
+
if (kind === "scalar") {
|
|
157
|
+
if (typeof value["codecId"] !== "string") return false;
|
|
158
|
+
const typeParams = value["typeParams"];
|
|
159
|
+
if (typeParams !== void 0 && !isPlainRecord(typeParams)) return false;
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (kind === "valueObject") return typeof value["name"] === "string";
|
|
163
|
+
if (kind === "union") {
|
|
164
|
+
const members = value["members"];
|
|
165
|
+
if (!Array.isArray(members)) return false;
|
|
166
|
+
return members.every((m) => isContractFieldType(m));
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
const ModelFieldSchema = type({
|
|
171
|
+
"+": "reject",
|
|
172
|
+
nullable: "boolean",
|
|
173
|
+
type: type("unknown").narrow((value, ctx) => isContractFieldType(value) ? true : ctx.mustBe("scalar, valueObject, or union field type")),
|
|
174
|
+
"many?": "true",
|
|
175
|
+
"dict?": "true"
|
|
176
|
+
});
|
|
177
|
+
const ModelSchema = type({
|
|
178
|
+
storage: type({
|
|
179
|
+
table: "string",
|
|
180
|
+
fields: type({ "[string]": type({
|
|
181
|
+
column: "string",
|
|
182
|
+
"codecId?": "string",
|
|
183
|
+
"nullable?": "boolean"
|
|
184
|
+
}) })
|
|
185
|
+
}),
|
|
186
|
+
"fields?": type({ "[string]": ModelFieldSchema }),
|
|
187
|
+
"relations?": type({ "[string]": "unknown" }),
|
|
188
|
+
"discriminator?": "unknown",
|
|
189
|
+
"variants?": "unknown",
|
|
190
|
+
"base?": "string",
|
|
191
|
+
"owner?": "string"
|
|
192
|
+
});
|
|
193
|
+
const SqlContractSchema = type({
|
|
194
|
+
"+": "reject",
|
|
195
|
+
target: "string",
|
|
196
|
+
targetFamily: "'sql'",
|
|
197
|
+
"coreHash?": "string",
|
|
198
|
+
profileHash: "string",
|
|
199
|
+
"capabilities?": "Record<string, Record<string, boolean>>",
|
|
200
|
+
"extensionPacks?": "Record<string, unknown>",
|
|
201
|
+
"meta?": type({ "[string]": "unknown" }),
|
|
202
|
+
"roots?": "Record<string, string>",
|
|
203
|
+
models: type({ "[string]": ModelSchema }),
|
|
204
|
+
"valueObjects?": "Record<string, unknown>",
|
|
205
|
+
storage: StorageSchema,
|
|
206
|
+
"execution?": ExecutionSchema
|
|
207
|
+
});
|
|
208
|
+
/**
|
|
209
|
+
* Validates the structural shape of SqlStorage using Arktype.
|
|
210
|
+
*
|
|
211
|
+
* @param value - The storage value to validate
|
|
212
|
+
* @returns The validated storage if structure is valid
|
|
213
|
+
* @throws Error if the storage structure is invalid
|
|
214
|
+
*/
|
|
215
|
+
function validateStorage(value) {
|
|
216
|
+
const result = StorageSchema(value);
|
|
217
|
+
if (result instanceof type.errors) {
|
|
218
|
+
const messages = result.map((p) => p.message).join("; ");
|
|
219
|
+
throw new Error(`Storage validation failed: ${messages}`);
|
|
220
|
+
}
|
|
221
|
+
return new SqlStorage(result);
|
|
222
|
+
}
|
|
223
|
+
function validateModel(value) {
|
|
224
|
+
const result = ModelSchema(value);
|
|
225
|
+
if (result instanceof type.errors) {
|
|
226
|
+
const messages = result.map((p) => p.message).join("; ");
|
|
227
|
+
throw new Error(`Model validation failed: ${messages}`);
|
|
228
|
+
}
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Structural arktype validation of an SQL contract envelope. Internal
|
|
233
|
+
* helper for {@link validateSqlContractFully} — exposed only inside
|
|
234
|
+
* this module, since the family seam-of-record is the
|
|
235
|
+
* `SqlContractSerializerBase.deserializeContract` SPI.
|
|
236
|
+
*/
|
|
237
|
+
function validateSqlContractStructure(value) {
|
|
238
|
+
if (typeof value !== "object" || value === null) throw new ContractValidationError("Contract structural validation failed: value must be an object", "structural");
|
|
239
|
+
const rawValue = value;
|
|
240
|
+
if (rawValue.targetFamily !== void 0 && rawValue.targetFamily !== "sql") throw new ContractValidationError(`Unsupported target family: ${rawValue.targetFamily}`, "structural");
|
|
241
|
+
const contractResult = SqlContractSchema(value);
|
|
242
|
+
if (contractResult instanceof type.errors) throw new ContractValidationError(`Contract structural validation failed: ${contractResult.map((p) => p.message).join("; ")}`, "structural");
|
|
243
|
+
return contractResult;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Validates semantic constraints on SqlStorage that cannot be expressed in Arktype schemas.
|
|
247
|
+
*
|
|
248
|
+
* Returns an array of human-readable error strings. Empty array = valid.
|
|
249
|
+
*
|
|
250
|
+
* Currently checks:
|
|
251
|
+
* - duplicate named primary key / unique / index / foreign key objects within a table
|
|
252
|
+
* - duplicate unique, index, or foreign key declarations within a table
|
|
253
|
+
* - duplicate columns within primary key / unique / index definitions
|
|
254
|
+
* - nullable columns in primary key definitions
|
|
255
|
+
* - `setNull` referential action on a non-nullable FK column (would fail at runtime)
|
|
256
|
+
* - `setDefault` referential action on a non-nullable FK column without a DEFAULT (would fail at runtime)
|
|
257
|
+
*/
|
|
258
|
+
function validateStorageSemantics(storage) {
|
|
259
|
+
const errors = [];
|
|
260
|
+
for (const [tableName, table] of Object.entries(storage.tables)) {
|
|
261
|
+
const namedObjects = /* @__PURE__ */ new Map();
|
|
262
|
+
const registerNamedObject = (kind, name) => {
|
|
263
|
+
if (!name) return;
|
|
264
|
+
namedObjects.set(name, [...namedObjects.get(name) ?? [], kind]);
|
|
265
|
+
};
|
|
266
|
+
registerNamedObject("primary key", table.primaryKey?.name);
|
|
267
|
+
for (const unique of table.uniques) registerNamedObject("unique constraint", unique.name);
|
|
268
|
+
for (const index of table.indexes) registerNamedObject("index", index.name);
|
|
269
|
+
for (const fk of table.foreignKeys) registerNamedObject("foreign key", fk.name);
|
|
270
|
+
for (const [name, kinds] of namedObjects) if (kinds.length > 1) errors.push(`Table "${tableName}": named object "${name}" is declared multiple times (${kinds.join(", ")})`);
|
|
271
|
+
if (table.primaryKey) {
|
|
272
|
+
const duplicateColumn = findDuplicateValue(table.primaryKey.columns);
|
|
273
|
+
if (duplicateColumn !== void 0) errors.push(`Table "${tableName}": primary key contains duplicate column "${duplicateColumn}"`);
|
|
274
|
+
for (const columnName of table.primaryKey.columns) if (table.columns[columnName]?.nullable === true) errors.push(`Table "${tableName}": primary key column "${columnName}" is nullable; primary key columns must be NOT NULL`);
|
|
275
|
+
}
|
|
276
|
+
const seenUniqueDefinitions = /* @__PURE__ */ new Set();
|
|
277
|
+
for (const unique of table.uniques) {
|
|
278
|
+
const duplicateColumn = findDuplicateValue(unique.columns);
|
|
279
|
+
if (duplicateColumn !== void 0) errors.push(`Table "${tableName}": unique constraint contains duplicate column "${duplicateColumn}"`);
|
|
280
|
+
const signature = JSON.stringify({ columns: unique.columns });
|
|
281
|
+
if (seenUniqueDefinitions.has(signature)) {
|
|
282
|
+
errors.push(`Table "${tableName}": duplicate unique constraint definition on columns [${unique.columns.join(", ")}]`);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
seenUniqueDefinitions.add(signature);
|
|
286
|
+
}
|
|
287
|
+
const sortOptions = (o) => o ? Object.fromEntries(Object.entries(o).sort(([a], [b]) => a.localeCompare(b))) : null;
|
|
288
|
+
const seenIndexDefinitions = /* @__PURE__ */ new Set();
|
|
289
|
+
for (const index of table.indexes) {
|
|
290
|
+
const duplicateColumn = findDuplicateValue(index.columns);
|
|
291
|
+
if (duplicateColumn !== void 0) errors.push(`Table "${tableName}": index contains duplicate column "${duplicateColumn}"`);
|
|
292
|
+
const signature = JSON.stringify({
|
|
293
|
+
columns: index.columns,
|
|
294
|
+
type: index.type ?? null,
|
|
295
|
+
options: sortOptions(index.options)
|
|
296
|
+
});
|
|
297
|
+
if (seenIndexDefinitions.has(signature)) {
|
|
298
|
+
errors.push(`Table "${tableName}": duplicate index definition on columns [${index.columns.join(", ")}]`);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
seenIndexDefinitions.add(signature);
|
|
302
|
+
}
|
|
303
|
+
const seenForeignKeyDefinitions = /* @__PURE__ */ new Set();
|
|
304
|
+
for (const fk of table.foreignKeys) {
|
|
305
|
+
const signature = JSON.stringify({
|
|
306
|
+
columns: fk.columns,
|
|
307
|
+
references: fk.references,
|
|
308
|
+
onDelete: fk.onDelete ?? null,
|
|
309
|
+
onUpdate: fk.onUpdate ?? null,
|
|
310
|
+
constraint: fk.constraint,
|
|
311
|
+
index: fk.index
|
|
312
|
+
});
|
|
313
|
+
if (seenForeignKeyDefinitions.has(signature)) {
|
|
314
|
+
errors.push(`Table "${tableName}": duplicate foreign key definition on columns [${fk.columns.join(", ")}]`);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
seenForeignKeyDefinitions.add(signature);
|
|
318
|
+
}
|
|
319
|
+
for (const fk of table.foreignKeys) for (const colName of fk.columns) {
|
|
320
|
+
const column = table.columns[colName];
|
|
321
|
+
if (!column) continue;
|
|
322
|
+
if (fk.onDelete === "setNull" && !column.nullable) errors.push(`Table "${tableName}": onDelete setNull on foreign key column "${colName}" which is NOT NULL`);
|
|
323
|
+
if (fk.onUpdate === "setNull" && !column.nullable) errors.push(`Table "${tableName}": onUpdate setNull on foreign key column "${colName}" which is NOT NULL`);
|
|
324
|
+
if (fk.onDelete === "setDefault" && !column.nullable && column.default === void 0) errors.push(`Table "${tableName}": onDelete setDefault on foreign key column "${colName}" which is NOT NULL and has no DEFAULT`);
|
|
325
|
+
if (fk.onUpdate === "setDefault" && !column.nullable && column.default === void 0) errors.push(`Table "${tableName}": onUpdate setDefault on foreign key column "${colName}" which is NOT NULL and has no DEFAULT`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return errors;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* SQL storage logical-consistency checks: every model.storage.table
|
|
332
|
+
* resolves to a real table, every model.storage.fields[*].column
|
|
333
|
+
* resolves to a real column, and value-object fields land on JSON-native
|
|
334
|
+
* columns. Throws `ContractValidationError` on the first mismatch.
|
|
335
|
+
*/
|
|
336
|
+
function validateModelStorageReferences(contract) {
|
|
337
|
+
const models = contract.models;
|
|
338
|
+
for (const [modelName, model] of Object.entries(models)) {
|
|
339
|
+
const storageTable = model.storage.table;
|
|
340
|
+
const table = contract.storage.tables[storageTable];
|
|
341
|
+
if (!table) throw new ContractValidationError(`Model "${modelName}" references non-existent table "${storageTable}"`, "storage");
|
|
342
|
+
const columnNames = new Set(Object.keys(table.columns));
|
|
343
|
+
for (const [fieldName, field] of Object.entries(model.storage.fields)) if (!columnNames.has(field.column)) throw new ContractValidationError(`Model "${modelName}" field "${fieldName}" references non-existent column "${field.column}" in table "${storageTable}"`, "storage");
|
|
344
|
+
const JSON_NATIVE_TYPES = new Set(["json", "jsonb"]);
|
|
345
|
+
for (const [fieldName, domainField] of Object.entries(model.fields ?? {})) {
|
|
346
|
+
if (domainField.type?.kind !== "valueObject") continue;
|
|
347
|
+
const storageField = model.storage.fields[fieldName];
|
|
348
|
+
if (!storageField) continue;
|
|
349
|
+
const column = table.columns[storageField.column];
|
|
350
|
+
if (!column) continue;
|
|
351
|
+
if (!JSON_NATIVE_TYPES.has(column.nativeType)) throw new ContractValidationError(`Model "${modelName}" field "${fieldName}" is a value object but storage column "${storageField.column}" has nativeType "${column.nativeType}" (expected json or jsonb)`, "storage");
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Cross-table consistency checks for SQL storage: primary key, unique,
|
|
357
|
+
* index, and foreign key column references resolve to real columns;
|
|
358
|
+
* NOT NULL columns don't carry a literal `null` default; FK column
|
|
359
|
+
* counts match their referenced columns. Throws on the first mismatch.
|
|
360
|
+
*/
|
|
361
|
+
function validateSqlStorageConsistency(contract) {
|
|
362
|
+
const tableNames = new Set(Object.keys(contract.storage.tables));
|
|
363
|
+
for (const [tableName, table] of Object.entries(contract.storage.tables)) {
|
|
364
|
+
const columnNames = new Set(Object.keys(table.columns));
|
|
365
|
+
if (table.primaryKey) {
|
|
366
|
+
for (const colName of table.primaryKey.columns) if (!columnNames.has(colName)) throw new ContractValidationError(`Table "${tableName}" primaryKey references non-existent column "${colName}"`, "storage");
|
|
367
|
+
}
|
|
368
|
+
for (const unique of table.uniques) for (const colName of unique.columns) if (!columnNames.has(colName)) throw new ContractValidationError(`Table "${tableName}" unique constraint references non-existent column "${colName}"`, "storage");
|
|
369
|
+
for (const index of table.indexes) for (const colName of index.columns) if (!columnNames.has(colName)) throw new ContractValidationError(`Table "${tableName}" index references non-existent column "${colName}"`, "storage");
|
|
370
|
+
for (const [colName, column] of Object.entries(table.columns)) if (!column.nullable && column.default?.kind === "literal" && column.default.value === null) throw new ContractValidationError(`Table "${tableName}" column "${colName}" is NOT NULL but has a literal null default`, "storage");
|
|
371
|
+
for (const fk of table.foreignKeys) {
|
|
372
|
+
for (const colName of fk.columns) if (!columnNames.has(colName)) throw new ContractValidationError(`Table "${tableName}" foreignKey references non-existent column "${colName}"`, "storage");
|
|
373
|
+
if (!tableNames.has(fk.references.table)) throw new ContractValidationError(`Table "${tableName}" foreignKey references non-existent table "${fk.references.table}"`, "storage");
|
|
374
|
+
const referencedTable = contract.storage.tables[fk.references.table];
|
|
375
|
+
if (!referencedTable) continue;
|
|
376
|
+
const referencedColumnNames = new Set(Object.keys(referencedTable.columns));
|
|
377
|
+
for (const colName of fk.references.columns) if (!referencedColumnNames.has(colName)) throw new ContractValidationError(`Table "${tableName}" foreignKey references non-existent column "${colName}" in table "${fk.references.table}"`, "storage");
|
|
378
|
+
if (fk.columns.length !== fk.references.columns.length) throw new ContractValidationError(`Table "${tableName}" foreignKey column count (${fk.columns.length}) does not match referenced column count (${fk.references.columns.length})`, "storage");
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Full SQL contract validation: structural (arktype) +
|
|
384
|
+
* framework-shared domain + SQL storage logical-consistency + SQL
|
|
385
|
+
* storage semantic + model ↔ storage reference checks. Throws
|
|
386
|
+
* `ContractValidationError` on the first failure. Returns the
|
|
387
|
+
* validated flat-data shape; IR class hydration happens in the SPI
|
|
388
|
+
* base on top of this helper.
|
|
389
|
+
*/
|
|
390
|
+
function validateSqlContractFully(value) {
|
|
391
|
+
const validated = validateSqlContractStructure(typeof value === "object" && value !== null ? (() => {
|
|
392
|
+
const { schemaVersion: _, _generated: _g, ...rest } = value;
|
|
393
|
+
return rest;
|
|
394
|
+
})() : value);
|
|
395
|
+
validateContractDomain({
|
|
396
|
+
roots: validated.roots,
|
|
397
|
+
models: validated.models,
|
|
398
|
+
...validated.valueObjects ? { valueObjects: validated.valueObjects } : {}
|
|
399
|
+
});
|
|
400
|
+
validateSqlStorageConsistency(validated);
|
|
401
|
+
const semanticErrors = validateStorageSemantics(validated.storage);
|
|
402
|
+
if (semanticErrors.length > 0) throw new ContractValidationError(`Contract semantic validation failed: ${semanticErrors.join("; ")}`, "storage");
|
|
403
|
+
validateModelStorageReferences(validated);
|
|
404
|
+
return validated;
|
|
405
|
+
}
|
|
406
|
+
//#endregion
|
|
407
|
+
export { ColumnDefaultFunctionSchema, ColumnDefaultLiteralSchema, ColumnDefaultSchema, ForeignKeyReferencesSchema, ForeignKeySchema, IndexSchema, ReferentialActionSchema, validateModel, validateModelStorageReferences, validateSqlContractFully, validateSqlStorageConsistency, validateStorage, validateStorageSemantics };
|
|
408
|
+
|
|
409
|
+
//# sourceMappingURL=validators.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.mjs","names":["f"],"sources":["../src/validators.ts"],"sourcesContent":["import { ContractValidationError } from '@prisma-next/contract/contract-validation-error';\nimport type { Contract, ContractField, ContractModel } from '@prisma-next/contract/types';\nimport { validateContractDomain } from '@prisma-next/contract/validate-domain';\nimport { type } from 'arktype';\nimport {\n type ForeignKeyInput,\n type ForeignKeyReferencesInput,\n type PrimaryKeyInput,\n type ReferentialAction,\n type SqlModelStorage,\n SqlStorage,\n type SqlStorageInput,\n type StorageTypeInstanceInput,\n type UniqueConstraintInput,\n} from './types';\n\ntype ColumnDefaultLiteral = {\n readonly kind: 'literal';\n readonly value: string | number | boolean | Record<string, unknown> | unknown[] | null;\n};\ntype ColumnDefaultFunction = { readonly kind: 'function'; readonly expression: string };\nconst literalKindSchema = type(\"'literal'\");\nconst functionKindSchema = type(\"'function'\");\nconst generatorKindSchema = type(\"'generator'\");\nconst generatorIdSchema = type('string').narrow((value, ctx) => {\n return /^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(value) ? true : ctx.mustBe('a flat generator id');\n});\n\nexport const ColumnDefaultLiteralSchema = type.declare<ColumnDefaultLiteral>().type({\n kind: literalKindSchema,\n value: 'string | number | boolean | null | unknown[] | Record<string, unknown>',\n});\n\nexport const ColumnDefaultFunctionSchema = type.declare<ColumnDefaultFunction>().type({\n kind: functionKindSchema,\n expression: 'string',\n});\n\nexport const ColumnDefaultSchema = ColumnDefaultLiteralSchema.or(ColumnDefaultFunctionSchema);\n\nconst ExecutionMutationDefaultValueSchema = type({\n '+': 'reject',\n kind: generatorKindSchema,\n id: generatorIdSchema,\n 'params?': 'Record<string, unknown>',\n});\n\nconst ExecutionMutationDefaultSchema = type({\n '+': 'reject',\n ref: {\n '+': 'reject',\n table: 'string',\n column: 'string',\n },\n 'onCreate?': ExecutionMutationDefaultValueSchema,\n 'onUpdate?': ExecutionMutationDefaultValueSchema,\n});\n\nconst ExecutionSchema = type({\n '+': 'reject',\n executionHash: 'string',\n mutations: {\n '+': 'reject',\n defaults: ExecutionMutationDefaultSchema.array().readonly(),\n },\n});\n\nconst StorageColumnSchema = type({\n '+': 'reject',\n nativeType: 'string',\n codecId: 'string',\n nullable: 'boolean',\n 'typeParams?': 'Record<string, unknown>',\n 'typeRef?': 'string',\n 'default?': ColumnDefaultSchema,\n}).narrow((col, ctx) => {\n if (col.typeParams !== undefined && col.typeRef !== undefined) {\n return ctx.mustBe('a column with either typeParams or typeRef, not both');\n }\n return true;\n});\n\n/**\n * Codec-triple entry persisted under `storage.types[name]`. Carries an\n * enumerable literal `kind: 'codec-instance'` discriminator so the\n * polymorphic slot dispatch can distinguish codec triples from\n * class-instance kinds (e.g. `'postgres-enum'`) sharing the slot.\n */\nconst StorageTypeInstanceSchema = type\n .declare<StorageTypeInstanceInput & { kind: 'codec-instance' }>()\n .type({\n kind: \"'codec-instance'\",\n codecId: 'string',\n nativeType: 'string',\n typeParams: 'Record<string, unknown>',\n });\n\n/**\n * Polymorphic enum-type entry under `storage.types[name]`. Carries an\n * enumerable literal `kind: 'postgres-enum'` discriminator so the\n * per-target hydration walker can dispatch cleanly back to a typed\n * IR-class instance during `deserializeContract`. The discriminator\n * reflects target-level behaviour (Postgres-native enums versus\n * family-layer codec triples) — not the family abstract altitude alone.\n *\n * The schema literal lives at the family layer today because\n * registry-driven validation for arbitrary slot shapes is not wired\n * yet; once a second polymorphic kind ships through the slot, this\n * structural enumeration can move to the registry-dispatch site and\n * per-target schemas can live in their target packages.\n */\nconst PostgresEnumTypeSchema = type({\n kind: \"'postgres-enum'\",\n name: 'string',\n nativeType: 'string',\n values: type.string.array().readonly(),\n});\n\n/**\n * Family-layer arktype validation enumerates the polymorphic shapes the\n * SQL family ships today (codec-instance + Postgres-enum). Pack-contributed\n * entity types ship a parallel arktype schema entry here when they\n * introduce a new persisted shape; the registry-driven hydration seam at\n * `SqlContractSerializerBase.hydrateStorageTypeEntry` is open, but the\n * family-layer structural validator is closed by design — extension\n * packs cannot inject arbitrary persisted shapes through the slot\n * without their structural shape being known at the family layer.\n *\n * A future refinement is to lift `StorageTypeEntrySchema` toward an\n * `unknown` fallback and move structural diagnostics to the\n * registry-dispatch site at hydration time, earned once a non-enum\n * storage shape needs to flow through the slot without growing another\n * closed union arm here first.\n */\nconst StorageTypeEntrySchema = PostgresEnumTypeSchema.or(StorageTypeInstanceSchema);\n\nconst PrimaryKeySchema = type.declare<PrimaryKeyInput>().type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n});\n\nconst UniqueConstraintSchema = type.declare<UniqueConstraintInput>().type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n});\n\nexport const IndexSchema = type({\n columns: type.string.array().readonly(),\n 'name?': 'string',\n 'type?': 'string',\n 'options?': 'Record<string, unknown>',\n});\n\nexport const ForeignKeyReferencesSchema = type.declare<ForeignKeyReferencesInput>().type({\n table: 'string',\n columns: type.string.array().readonly(),\n});\n\nexport const ReferentialActionSchema = type\n .declare<ReferentialAction>()\n .type(\"'noAction' | 'restrict' | 'cascade' | 'setNull' | 'setDefault'\");\n\nexport const ForeignKeySchema = type.declare<ForeignKeyInput>().type({\n columns: type.string.array().readonly(),\n references: ForeignKeyReferencesSchema,\n 'name?': 'string',\n 'onDelete?': ReferentialActionSchema,\n 'onUpdate?': ReferentialActionSchema,\n constraint: 'boolean',\n index: 'boolean',\n});\n\nconst StorageTableSchema = type({\n '+': 'reject',\n columns: type({ '[string]': StorageColumnSchema }),\n 'primaryKey?': PrimaryKeySchema,\n uniques: UniqueConstraintSchema.array().readonly(),\n indexes: IndexSchema.array().readonly(),\n foreignKeys: ForeignKeySchema.array().readonly(),\n});\n\n/**\n * Namespace entry under `storage.namespaces[id]`. SQL contracts honour\n * the framework `Storage.namespaces` invariant from PR1; today every\n * contract binds to the singleton placeholder\n * (`SqlUnspecifiedNamespace.instance`) and the persisted shape carries\n * just the namespace id. Per-target namespace concretions\n * (`PostgresSchema`, `SqliteUnspecifiedDatabase`) can additively grow\n * the persisted shape when they earn their slots.\n */\nconst NamespaceEntrySchema = type({\n id: 'string',\n});\n\nconst StorageSchema = type({\n '+': 'reject',\n storageHash: 'string',\n tables: type({ '[string]': StorageTableSchema }),\n 'types?': type({ '[string]': StorageTypeEntrySchema }),\n 'namespaces?': type({ '[string]': NamespaceEntrySchema }),\n});\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction findDuplicateValue(values: readonly string[]): string | undefined {\n const seen = new Set<string>();\n for (const value of values) {\n if (seen.has(value)) {\n return value;\n }\n seen.add(value);\n }\n return undefined;\n}\n\nfunction isContractFieldType(value: unknown): boolean {\n if (!isPlainRecord(value)) return false;\n const kind = value['kind'];\n if (kind === 'scalar') {\n if (typeof value['codecId'] !== 'string') return false;\n const typeParams = value['typeParams'];\n if (typeParams !== undefined && !isPlainRecord(typeParams)) return false;\n return true;\n }\n if (kind === 'valueObject') {\n return typeof value['name'] === 'string';\n }\n if (kind === 'union') {\n const members = value['members'];\n if (!Array.isArray(members)) return false;\n return members.every((m) => isContractFieldType(m));\n }\n return false;\n}\n\nconst ContractFieldTypeSchema = type('unknown').narrow((value, ctx) =>\n isContractFieldType(value) ? true : ctx.mustBe('scalar, valueObject, or union field type'),\n);\n\nconst ModelFieldSchema = type({\n '+': 'reject',\n nullable: 'boolean',\n type: ContractFieldTypeSchema,\n 'many?': 'true',\n 'dict?': 'true',\n});\n\nconst ModelStorageFieldSchema = type({\n column: 'string',\n 'codecId?': 'string',\n 'nullable?': 'boolean',\n});\n\nconst ModelStorageSchema = type({\n table: 'string',\n fields: type({ '[string]': ModelStorageFieldSchema }),\n});\n\nconst ModelSchema = type({\n storage: ModelStorageSchema,\n 'fields?': type({ '[string]': ModelFieldSchema }),\n 'relations?': type({ '[string]': 'unknown' }),\n 'discriminator?': 'unknown',\n 'variants?': 'unknown',\n 'base?': 'string',\n 'owner?': 'string',\n});\n\nconst ContractMetaSchema = type({\n '[string]': 'unknown',\n});\n\nconst SqlContractSchema = type({\n '+': 'reject',\n target: 'string',\n targetFamily: \"'sql'\",\n 'coreHash?': 'string',\n profileHash: 'string',\n 'capabilities?': 'Record<string, Record<string, boolean>>',\n 'extensionPacks?': 'Record<string, unknown>',\n 'meta?': ContractMetaSchema,\n 'roots?': 'Record<string, string>',\n models: type({ '[string]': ModelSchema }),\n 'valueObjects?': 'Record<string, unknown>',\n storage: StorageSchema,\n 'execution?': ExecutionSchema,\n});\n\n// NOTE: StorageColumnSchema, StorageTableSchema, and StorageSchema use bare type()\n// instead of type.declare<T>().type() because the ColumnDefault union's value field\n// includes bigint | Date (runtime-only types after decoding) which cannot be expressed\n// in Arktype's JSON validation DSL. The `as SqlStorage` cast in validateStorage() bridges\n// the gap between the JSON-safe Arktype output and the runtime TypeScript type.\n\n/**\n * Validates the structural shape of SqlStorage using Arktype.\n *\n * @param value - The storage value to validate\n * @returns The validated storage if structure is valid\n * @throws Error if the storage structure is invalid\n */\nexport function validateStorage(value: unknown): SqlStorage {\n const result = StorageSchema(value);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Storage validation failed: ${messages}`);\n }\n // The arktype-validated shape matches `SqlStorageInput`\n // structurally. Funnel through the constructor so nested IR fields\n // (`tables`, `types`) are normalised into class instances and the\n // branded `storageHash` is preserved on the returned `SqlStorage`.\n return new SqlStorage(result as SqlStorageInput);\n}\n\nexport function validateModel(value: unknown): unknown {\n const result = ModelSchema(value);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Model validation failed: ${messages}`);\n }\n return result;\n}\n\n/**\n * Structural arktype validation of an SQL contract envelope. Internal\n * helper for {@link validateSqlContractFully} — exposed only inside\n * this module, since the family seam-of-record is the\n * `SqlContractSerializerBase.deserializeContract` SPI.\n */\nfunction validateSqlContractStructure<T extends Contract<SqlStorage>>(value: unknown): T {\n if (typeof value !== 'object' || value === null) {\n throw new ContractValidationError(\n 'Contract structural validation failed: value must be an object',\n 'structural',\n );\n }\n\n const rawValue = value as { targetFamily?: string };\n if (rawValue.targetFamily !== undefined && rawValue.targetFamily !== 'sql') {\n throw new ContractValidationError(\n `Unsupported target family: ${rawValue.targetFamily}`,\n 'structural',\n );\n }\n\n const contractResult = SqlContractSchema(value);\n\n if (contractResult instanceof type.errors) {\n const messages = contractResult.map((p: { message: string }) => p.message).join('; ');\n throw new ContractValidationError(\n `Contract structural validation failed: ${messages}`,\n 'structural',\n );\n }\n\n // Arktype's inferred output type differs from T due to exactOptionalPropertyTypes\n // and branded hash types — the runtime value is structurally compatible after validation\n return contractResult as unknown as T;\n}\n\n/**\n * Validates semantic constraints on SqlStorage that cannot be expressed in Arktype schemas.\n *\n * Returns an array of human-readable error strings. Empty array = valid.\n *\n * Currently checks:\n * - duplicate named primary key / unique / index / foreign key objects within a table\n * - duplicate unique, index, or foreign key declarations within a table\n * - duplicate columns within primary key / unique / index definitions\n * - nullable columns in primary key definitions\n * - `setNull` referential action on a non-nullable FK column (would fail at runtime)\n * - `setDefault` referential action on a non-nullable FK column without a DEFAULT (would fail at runtime)\n */\nexport function validateStorageSemantics(storage: SqlStorage): string[] {\n const errors: string[] = [];\n\n for (const [tableName, table] of Object.entries(storage.tables)) {\n const namedObjects = new Map<string, string[]>();\n const registerNamedObject = (kind: string, name: string | undefined) => {\n if (!name) return;\n namedObjects.set(name, [...(namedObjects.get(name) ?? []), kind]);\n };\n\n registerNamedObject('primary key', table.primaryKey?.name);\n for (const unique of table.uniques) {\n registerNamedObject('unique constraint', unique.name);\n }\n for (const index of table.indexes) {\n registerNamedObject('index', index.name);\n }\n for (const fk of table.foreignKeys) {\n registerNamedObject('foreign key', fk.name);\n }\n\n for (const [name, kinds] of namedObjects) {\n if (kinds.length > 1) {\n errors.push(\n `Table \"${tableName}\": named object \"${name}\" is declared multiple times (${kinds.join(', ')})`,\n );\n }\n }\n\n if (table.primaryKey) {\n const duplicateColumn = findDuplicateValue(table.primaryKey.columns);\n if (duplicateColumn !== undefined) {\n errors.push(\n `Table \"${tableName}\": primary key contains duplicate column \"${duplicateColumn}\"`,\n );\n }\n\n for (const columnName of table.primaryKey.columns) {\n const column = table.columns[columnName];\n if (column?.nullable === true) {\n errors.push(\n `Table \"${tableName}\": primary key column \"${columnName}\" is nullable; primary key columns must be NOT NULL`,\n );\n }\n }\n }\n\n const seenUniqueDefinitions = new Set<string>();\n for (const unique of table.uniques) {\n const duplicateColumn = findDuplicateValue(unique.columns);\n if (duplicateColumn !== undefined) {\n errors.push(\n `Table \"${tableName}\": unique constraint contains duplicate column \"${duplicateColumn}\"`,\n );\n }\n\n const signature = JSON.stringify({ columns: unique.columns });\n if (seenUniqueDefinitions.has(signature)) {\n errors.push(\n `Table \"${tableName}\": duplicate unique constraint definition on columns [${unique.columns.join(', ')}]`,\n );\n continue;\n }\n seenUniqueDefinitions.add(signature);\n }\n\n const sortOptions = (o: Record<string, unknown> | undefined): Record<string, unknown> | null =>\n o ? Object.fromEntries(Object.entries(o).sort(([a], [b]) => a.localeCompare(b))) : null;\n\n const seenIndexDefinitions = new Set<string>();\n for (const index of table.indexes) {\n const duplicateColumn = findDuplicateValue(index.columns);\n if (duplicateColumn !== undefined) {\n errors.push(`Table \"${tableName}\": index contains duplicate column \"${duplicateColumn}\"`);\n }\n\n const signature = JSON.stringify({\n columns: index.columns,\n type: index.type ?? null,\n options: sortOptions(index.options),\n });\n if (seenIndexDefinitions.has(signature)) {\n errors.push(\n `Table \"${tableName}\": duplicate index definition on columns [${index.columns.join(', ')}]`,\n );\n continue;\n }\n seenIndexDefinitions.add(signature);\n }\n\n const seenForeignKeyDefinitions = new Set<string>();\n for (const fk of table.foreignKeys) {\n const signature = JSON.stringify({\n columns: fk.columns,\n references: fk.references,\n onDelete: fk.onDelete ?? null,\n onUpdate: fk.onUpdate ?? null,\n constraint: fk.constraint,\n index: fk.index,\n });\n if (seenForeignKeyDefinitions.has(signature)) {\n errors.push(\n `Table \"${tableName}\": duplicate foreign key definition on columns [${fk.columns.join(', ')}]`,\n );\n continue;\n }\n seenForeignKeyDefinitions.add(signature);\n }\n\n for (const fk of table.foreignKeys) {\n for (const colName of fk.columns) {\n const column = table.columns[colName];\n if (!column) continue;\n\n if (fk.onDelete === 'setNull' && !column.nullable) {\n errors.push(\n `Table \"${tableName}\": onDelete setNull on foreign key column \"${colName}\" which is NOT NULL`,\n );\n }\n if (fk.onUpdate === 'setNull' && !column.nullable) {\n errors.push(\n `Table \"${tableName}\": onUpdate setNull on foreign key column \"${colName}\" which is NOT NULL`,\n );\n }\n if (fk.onDelete === 'setDefault' && !column.nullable && column.default === undefined) {\n errors.push(\n `Table \"${tableName}\": onDelete setDefault on foreign key column \"${colName}\" which is NOT NULL and has no DEFAULT`,\n );\n }\n if (fk.onUpdate === 'setDefault' && !column.nullable && column.default === undefined) {\n errors.push(\n `Table \"${tableName}\": onUpdate setDefault on foreign key column \"${colName}\" which is NOT NULL and has no DEFAULT`,\n );\n }\n }\n }\n }\n\n return errors;\n}\n\n/**\n * SQL storage logical-consistency checks: every model.storage.table\n * resolves to a real table, every model.storage.fields[*].column\n * resolves to a real column, and value-object fields land on JSON-native\n * columns. Throws `ContractValidationError` on the first mismatch.\n */\nexport function validateModelStorageReferences(contract: Contract<SqlStorage>): void {\n const models = contract.models as Record<string, ContractModel<SqlModelStorage>>;\n for (const [modelName, model] of Object.entries(models)) {\n const storageTable = model.storage.table;\n\n const table = contract.storage.tables[storageTable] as\n | (typeof contract.storage.tables)[string]\n | undefined;\n if (!table) {\n throw new ContractValidationError(\n `Model \"${modelName}\" references non-existent table \"${storageTable}\"`,\n 'storage',\n );\n }\n\n const columnNames = new Set(Object.keys(table.columns));\n for (const [fieldName, field] of Object.entries(model.storage.fields)) {\n if (!columnNames.has(field.column)) {\n throw new ContractValidationError(\n `Model \"${modelName}\" field \"${fieldName}\" references non-existent column \"${field.column}\" in table \"${storageTable}\"`,\n 'storage',\n );\n }\n }\n\n const JSON_NATIVE_TYPES = new Set(['json', 'jsonb']);\n for (const [fieldName, domainField] of Object.entries(model.fields ?? {})) {\n const f = domainField as ContractField;\n if (f.type?.kind !== 'valueObject') continue;\n const storageField = model.storage.fields[fieldName];\n if (!storageField) continue;\n const column = table.columns[storageField.column];\n if (!column) continue;\n if (!JSON_NATIVE_TYPES.has(column.nativeType)) {\n throw new ContractValidationError(\n `Model \"${modelName}\" field \"${fieldName}\" is a value object but storage column \"${storageField.column}\" has nativeType \"${column.nativeType}\" (expected json or jsonb)`,\n 'storage',\n );\n }\n }\n }\n}\n\n/**\n * Cross-table consistency checks for SQL storage: primary key, unique,\n * index, and foreign key column references resolve to real columns;\n * NOT NULL columns don't carry a literal `null` default; FK column\n * counts match their referenced columns. Throws on the first mismatch.\n */\nexport function validateSqlStorageConsistency(contract: Contract<SqlStorage>): void {\n const tableNames = new Set(Object.keys(contract.storage.tables));\n\n for (const [tableName, table] of Object.entries(contract.storage.tables)) {\n const columnNames = new Set(Object.keys(table.columns));\n\n if (table.primaryKey) {\n for (const colName of table.primaryKey.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Table \"${tableName}\" primaryKey references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const unique of table.uniques) {\n for (const colName of unique.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Table \"${tableName}\" unique constraint references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const index of table.indexes) {\n for (const colName of index.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Table \"${tableName}\" index references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n }\n\n for (const [colName, column] of Object.entries(table.columns)) {\n if (!column.nullable && column.default?.kind === 'literal' && column.default.value === null) {\n throw new ContractValidationError(\n `Table \"${tableName}\" column \"${colName}\" is NOT NULL but has a literal null default`,\n 'storage',\n );\n }\n }\n\n for (const fk of table.foreignKeys) {\n for (const colName of fk.columns) {\n if (!columnNames.has(colName)) {\n throw new ContractValidationError(\n `Table \"${tableName}\" foreignKey references non-existent column \"${colName}\"`,\n 'storage',\n );\n }\n }\n\n if (!tableNames.has(fk.references.table)) {\n throw new ContractValidationError(\n `Table \"${tableName}\" foreignKey references non-existent table \"${fk.references.table}\"`,\n 'storage',\n );\n }\n\n const referencedTable = contract.storage.tables[fk.references.table];\n if (!referencedTable) continue;\n const referencedColumnNames = new Set(Object.keys(referencedTable.columns));\n for (const colName of fk.references.columns) {\n if (!referencedColumnNames.has(colName)) {\n throw new ContractValidationError(\n `Table \"${tableName}\" foreignKey references non-existent column \"${colName}\" in table \"${fk.references.table}\"`,\n 'storage',\n );\n }\n }\n\n if (fk.columns.length !== fk.references.columns.length) {\n throw new ContractValidationError(\n `Table \"${tableName}\" foreignKey column count (${fk.columns.length}) does not match referenced column count (${fk.references.columns.length})`,\n 'storage',\n );\n }\n }\n }\n}\n\n/**\n * Full SQL contract validation: structural (arktype) +\n * framework-shared domain + SQL storage logical-consistency + SQL\n * storage semantic + model ↔ storage reference checks. Throws\n * `ContractValidationError` on the first failure. Returns the\n * validated flat-data shape; IR class hydration happens in the SPI\n * base on top of this helper.\n */\nexport function validateSqlContractFully<T extends Contract<SqlStorage>>(value: unknown): T {\n const stripped =\n typeof value === 'object' && value !== null\n ? (() => {\n const { schemaVersion: _, _generated: _g, ...rest } = value as Record<string, unknown>;\n return rest;\n })()\n : value;\n const validated = validateSqlContractStructure<T>(stripped);\n validateContractDomain({\n roots: validated.roots,\n models: validated.models,\n ...(validated.valueObjects ? { valueObjects: validated.valueObjects } : {}),\n });\n validateSqlStorageConsistency(validated);\n const semanticErrors = validateStorageSemantics(validated.storage);\n if (semanticErrors.length > 0) {\n throw new ContractValidationError(\n `Contract semantic validation failed: ${semanticErrors.join('; ')}`,\n 'storage',\n );\n }\n validateModelStorageReferences(validated);\n return validated;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-dev.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "SQL contract types, validators, and IR factories for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/contract": "0.
|
|
10
|
-
"@prisma-next/framework-components": "0.
|
|
9
|
+
"@prisma-next/contract": "0.9.0-dev.1",
|
|
10
|
+
"@prisma-next/framework-components": "0.9.0-dev.1",
|
|
11
11
|
"arktype": "^2.1.29"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@prisma-next/test-utils": "0.
|
|
15
|
-
"@prisma-next/tsconfig": "0.
|
|
16
|
-
"@prisma-next/tsdown": "0.
|
|
14
|
+
"@prisma-next/test-utils": "0.9.0-dev.1",
|
|
15
|
+
"@prisma-next/tsconfig": "0.9.0-dev.1",
|
|
16
|
+
"@prisma-next/tsdown": "0.9.0-dev.1",
|
|
17
17
|
"tsdown": "0.22.0",
|
|
18
18
|
"typescript": "5.9.3",
|
|
19
19
|
"vitest": "4.1.5"
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
"./index-types": "./dist/index-types.mjs",
|
|
29
29
|
"./pack-types": "./dist/pack-types.mjs",
|
|
30
30
|
"./types": "./dist/types.mjs",
|
|
31
|
-
"./validate": "./dist/validate.mjs",
|
|
32
31
|
"./validators": "./dist/validators.mjs",
|
|
33
32
|
"./package.json": "./package.json"
|
|
34
33
|
},
|
package/src/exports/types.ts
CHANGED
|
@@ -8,11 +8,12 @@ export type {
|
|
|
8
8
|
ExtractTypeMapsFromContract,
|
|
9
9
|
FieldInputTypesOf,
|
|
10
10
|
FieldOutputTypesOf,
|
|
11
|
-
|
|
11
|
+
ForeignKeyInput,
|
|
12
12
|
ForeignKeyOptions,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
ForeignKeyReferencesInput,
|
|
14
|
+
IndexInput,
|
|
15
|
+
PostgresEnumStorageEntry,
|
|
16
|
+
PrimaryKeyInput,
|
|
16
17
|
QueryOperationReturn,
|
|
17
18
|
QueryOperationSelfSpec,
|
|
18
19
|
QueryOperationTypeEntry,
|
|
@@ -23,13 +24,33 @@ export type {
|
|
|
23
24
|
SqlModelFieldStorage,
|
|
24
25
|
SqlModelStorage,
|
|
25
26
|
SqlQueryOperationTypes,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
SqlStorageInput,
|
|
28
|
+
SqlStorageTypeEntry,
|
|
29
|
+
StorageColumnInput,
|
|
30
|
+
StorageTableInput,
|
|
29
31
|
StorageTypeInstance,
|
|
32
|
+
StorageTypeInstanceInput,
|
|
30
33
|
TypeMaps,
|
|
31
34
|
TypeMapsPhantomKey,
|
|
35
|
+
UniqueConstraintInput,
|
|
36
|
+
} from '../types';
|
|
37
|
+
export {
|
|
38
|
+
applyFkDefaults,
|
|
39
|
+
CODEC_INSTANCE_KIND,
|
|
40
|
+
DEFAULT_FK_CONSTRAINT,
|
|
41
|
+
DEFAULT_FK_INDEX,
|
|
42
|
+
ForeignKey,
|
|
43
|
+
ForeignKeyReferences,
|
|
44
|
+
Index,
|
|
45
|
+
isPostgresEnumStorageEntry,
|
|
46
|
+
isStorageTypeInstance,
|
|
47
|
+
POSTGRES_ENUM_KIND,
|
|
48
|
+
PrimaryKey,
|
|
49
|
+
SqlNode,
|
|
50
|
+
SqlStorage,
|
|
51
|
+
SqlUnspecifiedNamespace,
|
|
52
|
+
StorageColumn,
|
|
53
|
+
StorageTable,
|
|
54
|
+
toStorageTypeInstance,
|
|
32
55
|
UniqueConstraint,
|
|
33
56
|
} from '../types';
|
|
34
|
-
|
|
35
|
-
export { applyFkDefaults, DEFAULT_FK_CONSTRAINT, DEFAULT_FK_INDEX } from '../types';
|