@prisma-next/sql-runtime 0.3.0-dev.4 → 0.3.0-dev.41
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 +116 -26
- package/dist/exports-C8hi0N-a.mjs +622 -0
- package/dist/exports-C8hi0N-a.mjs.map +1 -0
- package/dist/index-SlQIrV_t.d.mts +131 -0
- package/dist/index-SlQIrV_t.d.mts.map +1 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +3 -0
- package/dist/test/utils.d.mts +82 -0
- package/dist/test/utils.d.mts.map +1 -0
- package/dist/test/utils.mjs +212 -0
- package/dist/test/utils.mjs.map +1 -0
- package/package.json +35 -26
- package/src/codecs/decoding.ts +221 -0
- package/src/codecs/encoding.ts +89 -0
- package/src/codecs/json-schema-validation.ts +61 -0
- package/src/codecs/validation.ts +67 -0
- package/src/exports/index.ts +45 -0
- package/src/lower-sql-plan.ts +32 -0
- package/src/sql-context.ts +443 -0
- package/src/sql-family-adapter.ts +47 -0
- package/src/sql-marker.ts +105 -0
- package/src/sql-runtime.ts +232 -0
- package/test/async-iterable-result.test.ts +144 -0
- package/test/context.types.test-d.ts +68 -0
- package/test/execution-stack.test.ts +166 -0
- package/test/json-schema-validation.test.ts +653 -0
- package/test/parameterized-types.test.ts +539 -0
- package/test/sql-context.test.ts +392 -0
- package/test/sql-family-adapter.test.ts +87 -0
- package/test/sql-runtime.test.ts +241 -0
- package/test/utils.ts +291 -0
- package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
- package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
- package/dist/amcheck-24VY6X5V.js +0 -13
- package/dist/amcheck-24VY6X5V.js.map +0 -1
- package/dist/bloom-VS74NLHT.js +0 -13
- package/dist/bloom-VS74NLHT.js.map +0 -1
- package/dist/btree_gin-WBC4EAAI.js +0 -13
- package/dist/btree_gin-WBC4EAAI.js.map +0 -1
- package/dist/btree_gist-UNC6QD3M.js +0 -13
- package/dist/btree_gist-UNC6QD3M.js.map +0 -1
- package/dist/chunk-3KTOEDFX.js +0 -49
- package/dist/chunk-3KTOEDFX.js.map +0 -1
- package/dist/chunk-47DZBRQC.js +0 -1280
- package/dist/chunk-47DZBRQC.js.map +0 -1
- package/dist/chunk-52N6AFZM.js +0 -133
- package/dist/chunk-52N6AFZM.js.map +0 -1
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-7D4SUZUM.js.map +0 -1
- package/dist/chunk-C6I3V3DM.js +0 -455
- package/dist/chunk-C6I3V3DM.js.map +0 -1
- package/dist/chunk-ECWIHLAT.js +0 -37
- package/dist/chunk-ECWIHLAT.js.map +0 -1
- package/dist/chunk-EI626SDC.js +0 -105
- package/dist/chunk-EI626SDC.js.map +0 -1
- package/dist/chunk-UKKOYUGL.js +0 -578
- package/dist/chunk-UKKOYUGL.js.map +0 -1
- package/dist/chunk-XPLNMXQV.js +0 -1537
- package/dist/chunk-XPLNMXQV.js.map +0 -1
- package/dist/citext-T7MXGUY7.js +0 -13
- package/dist/citext-T7MXGUY7.js.map +0 -1
- package/dist/client-5FENX6AW.js +0 -299
- package/dist/client-5FENX6AW.js.map +0 -1
- package/dist/cube-TFDQBZCI.js +0 -13
- package/dist/cube-TFDQBZCI.js.map +0 -1
- package/dist/dict_int-AEUOPGWP.js +0 -13
- package/dist/dict_int-AEUOPGWP.js.map +0 -1
- package/dist/dict_xsyn-DAAYX3FL.js +0 -13
- package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
- package/dist/dist-AQ3LWXOX.js +0 -570
- package/dist/dist-AQ3LWXOX.js.map +0 -1
- package/dist/dist-LBVX6BJW.js +0 -189
- package/dist/dist-LBVX6BJW.js.map +0 -1
- package/dist/dist-WLKUVDN2.js +0 -5127
- package/dist/dist-WLKUVDN2.js.map +0 -1
- package/dist/earthdistance-KIGTF4LE.js +0 -13
- package/dist/earthdistance-KIGTF4LE.js.map +0 -1
- package/dist/file_fdw-5N55UP6I.js +0 -13
- package/dist/file_fdw-5N55UP6I.js.map +0 -1
- package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
- package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
- package/dist/hstore-YX726NKN.js +0 -13
- package/dist/hstore-YX726NKN.js.map +0 -1
- package/dist/http-exception-FZY2H4OF.js +0 -8
- package/dist/http-exception-FZY2H4OF.js.map +0 -1
- package/dist/index.d.ts +0 -29
- package/dist/index.js +0 -30
- package/dist/index.js.map +0 -1
- package/dist/intarray-NKVXNO2D.js +0 -13
- package/dist/intarray-NKVXNO2D.js.map +0 -1
- package/dist/isn-FTEMJGEV.js +0 -13
- package/dist/isn-FTEMJGEV.js.map +0 -1
- package/dist/lo-DB7L4NGI.js +0 -13
- package/dist/lo-DB7L4NGI.js.map +0 -1
- package/dist/logger-WQ7SHNDD.js +0 -68
- package/dist/logger-WQ7SHNDD.js.map +0 -1
- package/dist/ltree-Z32TZT6W.js +0 -13
- package/dist/ltree-Z32TZT6W.js.map +0 -1
- package/dist/nodefs-NM46ACH7.js +0 -31
- package/dist/nodefs-NM46ACH7.js.map +0 -1
- package/dist/opfs-ahp-NJO33LVZ.js +0 -332
- package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
- package/dist/pageinspect-YP3IZR4X.js +0 -13
- package/dist/pageinspect-YP3IZR4X.js.map +0 -1
- package/dist/pg_buffercache-7TD5J2FB.js +0 -13
- package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
- package/dist/pg_dump-SG4KYBUB.js +0 -2492
- package/dist/pg_dump-SG4KYBUB.js.map +0 -1
- package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
- package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
- package/dist/pg_surgery-J2MUEWEP.js +0 -13
- package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
- package/dist/pg_trgm-7VNQOYS6.js +0 -13
- package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
- package/dist/pg_visibility-TTSIPHFL.js +0 -13
- package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
- package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
- package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
- package/dist/proxy-signals-GUDAMDHV.js +0 -39
- package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
- package/dist/seg-IYVDLE4O.js +0 -13
- package/dist/seg-IYVDLE4O.js.map +0 -1
- package/dist/sql-runtime-DgEbg2OP.d.ts +0 -109
- package/dist/tablefunc-EF4RCS7S.js +0 -13
- package/dist/tablefunc-EF4RCS7S.js.map +0 -1
- package/dist/tcn-3VT5BQYW.js +0 -13
- package/dist/tcn-3VT5BQYW.js.map +0 -1
- package/dist/test/utils.d.ts +0 -64
- package/dist/test/utils.js +0 -24634
- package/dist/test/utils.js.map +0 -1
- package/dist/tiny-CW6F4GX6.js +0 -10
- package/dist/tiny-CW6F4GX6.js.map +0 -1
- package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
- package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
- package/dist/tsm_system_time-76WEIMBG.js +0 -13
- package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
- package/dist/unaccent-7RYF3R64.js +0 -13
- package/dist/unaccent-7RYF3R64.js.map +0 -1
- package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
- package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
- package/dist/uuid_ossp-4ETE4FPE.js +0 -13
- package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
- package/dist/vector-74GPNV7V.js +0 -13
- package/dist/vector-74GPNV7V.js.map +0 -1
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
import { AsyncIterableResult, budgets, createRuntimeCore, lints, runtimeError } from "@prisma-next/runtime-executor";
|
|
2
|
+
import { checkContractComponentRequirements } from "@prisma-next/contract/framework-components";
|
|
3
|
+
import { createExecutionStack } from "@prisma-next/core-execution-plane/stack";
|
|
4
|
+
import { generateId } from "@prisma-next/ids/runtime";
|
|
5
|
+
import { createOperationRegistry } from "@prisma-next/operations";
|
|
6
|
+
import { createCodecRegistry } from "@prisma-next/sql-relational-core/ast";
|
|
7
|
+
import { type } from "arktype";
|
|
8
|
+
import { ifDefined } from "@prisma-next/utils/defined";
|
|
9
|
+
|
|
10
|
+
//#region src/codecs/validation.ts
|
|
11
|
+
function extractCodecIds(contract) {
|
|
12
|
+
const codecIds = /* @__PURE__ */ new Set();
|
|
13
|
+
for (const table of Object.values(contract.storage.tables)) for (const column of Object.values(table.columns)) {
|
|
14
|
+
const codecId = column.codecId;
|
|
15
|
+
codecIds.add(codecId);
|
|
16
|
+
}
|
|
17
|
+
return codecIds;
|
|
18
|
+
}
|
|
19
|
+
function extractCodecIdsFromColumns(contract) {
|
|
20
|
+
const codecIds = /* @__PURE__ */ new Map();
|
|
21
|
+
for (const [tableName, table] of Object.entries(contract.storage.tables)) for (const [columnName, column] of Object.entries(table.columns)) {
|
|
22
|
+
const codecId = column.codecId;
|
|
23
|
+
const key = `${tableName}.${columnName}`;
|
|
24
|
+
codecIds.set(key, codecId);
|
|
25
|
+
}
|
|
26
|
+
return codecIds;
|
|
27
|
+
}
|
|
28
|
+
function validateContractCodecMappings(registry, contract) {
|
|
29
|
+
const codecIds = extractCodecIdsFromColumns(contract);
|
|
30
|
+
const invalidCodecs = [];
|
|
31
|
+
for (const [key, codecId] of codecIds.entries()) if (!registry.has(codecId)) {
|
|
32
|
+
const parts = key.split(".");
|
|
33
|
+
const table = parts[0] ?? "";
|
|
34
|
+
const column = parts[1] ?? "";
|
|
35
|
+
invalidCodecs.push({
|
|
36
|
+
table,
|
|
37
|
+
column,
|
|
38
|
+
codecId
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (invalidCodecs.length > 0) {
|
|
42
|
+
const details = {
|
|
43
|
+
contractTarget: contract.target,
|
|
44
|
+
invalidCodecs
|
|
45
|
+
};
|
|
46
|
+
throw runtimeError("RUNTIME.CODEC_MISSING", `Missing codec implementations for column codecIds: ${invalidCodecs.map((c) => `${c.table}.${c.column} (${c.codecId})`).join(", ")}`, details);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function validateCodecRegistryCompleteness(registry, contract) {
|
|
50
|
+
validateContractCodecMappings(registry, contract);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/lower-sql-plan.ts
|
|
55
|
+
/**
|
|
56
|
+
* Lowers a SQL query plan to an executable Plan by calling the adapter's lower method.
|
|
57
|
+
*
|
|
58
|
+
* @param adapter - Adapter to lower AST to SQL
|
|
59
|
+
* @param contract - Contract for lowering context
|
|
60
|
+
* @param queryPlan - SQL query plan from a lane (contains AST, params, meta, but no SQL)
|
|
61
|
+
* @returns Fully executable Plan with SQL string
|
|
62
|
+
*/
|
|
63
|
+
function lowerSqlPlan(adapter, contract, queryPlan) {
|
|
64
|
+
const body = adapter.lower(queryPlan.ast, {
|
|
65
|
+
contract,
|
|
66
|
+
params: queryPlan.params
|
|
67
|
+
}).body;
|
|
68
|
+
return Object.freeze({
|
|
69
|
+
sql: body.sql,
|
|
70
|
+
params: body.params ?? queryPlan.params,
|
|
71
|
+
ast: queryPlan.ast,
|
|
72
|
+
meta: queryPlan.meta
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/sql-context.ts
|
|
78
|
+
function createSqlExecutionStack(options) {
|
|
79
|
+
return createExecutionStack({
|
|
80
|
+
target: options.target,
|
|
81
|
+
adapter: options.adapter,
|
|
82
|
+
driver: options.driver,
|
|
83
|
+
extensionPacks: options.extensionPacks
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function assertExecutionStackContractRequirements(contract, stack) {
|
|
87
|
+
const providedComponentIds = new Set([
|
|
88
|
+
stack.target.id,
|
|
89
|
+
stack.adapter.id,
|
|
90
|
+
...stack.extensionPacks.map((pack) => pack.id)
|
|
91
|
+
]);
|
|
92
|
+
const result = checkContractComponentRequirements({
|
|
93
|
+
contract,
|
|
94
|
+
expectedTargetFamily: "sql",
|
|
95
|
+
expectedTargetId: stack.target.targetId,
|
|
96
|
+
providedComponentIds
|
|
97
|
+
});
|
|
98
|
+
if (result.familyMismatch) throw runtimeError("RUNTIME.CONTRACT_FAMILY_MISMATCH", `Contract target family '${result.familyMismatch.actual}' does not match runtime family '${result.familyMismatch.expected}'.`, {
|
|
99
|
+
actual: result.familyMismatch.actual,
|
|
100
|
+
expected: result.familyMismatch.expected
|
|
101
|
+
});
|
|
102
|
+
if (result.targetMismatch) throw runtimeError("RUNTIME.CONTRACT_TARGET_MISMATCH", `Contract target '${result.targetMismatch.actual}' does not match runtime target descriptor '${result.targetMismatch.expected}'.`, {
|
|
103
|
+
actual: result.targetMismatch.actual,
|
|
104
|
+
expected: result.targetMismatch.expected
|
|
105
|
+
});
|
|
106
|
+
if (result.missingExtensionPackIds.length > 0) {
|
|
107
|
+
const packIds = result.missingExtensionPackIds;
|
|
108
|
+
throw runtimeError("RUNTIME.MISSING_EXTENSION_PACK", `Contract requires extension pack(s) ${packIds.map((id) => `'${id}'`).join(", ")}, but runtime descriptors do not provide matching component(s).`, { packIds });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function validateTypeParams(typeParams, codecDescriptor, context) {
|
|
112
|
+
const result = codecDescriptor.paramsSchema(typeParams);
|
|
113
|
+
if (result instanceof type.errors) {
|
|
114
|
+
const messages = result.map((p) => p.message).join("; ");
|
|
115
|
+
throw runtimeError("RUNTIME.TYPE_PARAMS_INVALID", `Invalid typeParams for ${context.typeName ? `type '${context.typeName}'` : `column '${context.tableName}.${context.columnName}'`} (codecId: ${codecDescriptor.codecId}): ${messages}`, {
|
|
116
|
+
...context,
|
|
117
|
+
codecId: codecDescriptor.codecId,
|
|
118
|
+
typeParams
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
function collectParameterizedCodecDescriptors(contributors) {
|
|
124
|
+
const descriptors = /* @__PURE__ */ new Map();
|
|
125
|
+
for (const contributor of contributors) for (const descriptor of contributor.parameterizedCodecs()) {
|
|
126
|
+
if (descriptors.has(descriptor.codecId)) throw runtimeError("RUNTIME.DUPLICATE_PARAMETERIZED_CODEC", `Duplicate parameterized codec descriptor for codecId '${descriptor.codecId}'.`, { codecId: descriptor.codecId });
|
|
127
|
+
descriptors.set(descriptor.codecId, descriptor);
|
|
128
|
+
}
|
|
129
|
+
return descriptors;
|
|
130
|
+
}
|
|
131
|
+
function initializeTypeHelpers(storageTypes, codecDescriptors) {
|
|
132
|
+
const helpers = {};
|
|
133
|
+
if (!storageTypes) return helpers;
|
|
134
|
+
for (const [typeName, typeInstance] of Object.entries(storageTypes)) {
|
|
135
|
+
const descriptor = codecDescriptors.get(typeInstance.codecId);
|
|
136
|
+
if (descriptor) {
|
|
137
|
+
const validatedParams = validateTypeParams(typeInstance.typeParams, descriptor, { typeName });
|
|
138
|
+
if (descriptor.init) helpers[typeName] = descriptor.init(validatedParams);
|
|
139
|
+
else helpers[typeName] = typeInstance;
|
|
140
|
+
} else helpers[typeName] = typeInstance;
|
|
141
|
+
}
|
|
142
|
+
return helpers;
|
|
143
|
+
}
|
|
144
|
+
function validateColumnTypeParams(storage, codecDescriptors) {
|
|
145
|
+
for (const [tableName, table] of Object.entries(storage.tables)) for (const [columnName, column] of Object.entries(table.columns)) if (column.typeParams) {
|
|
146
|
+
const descriptor = codecDescriptors.get(column.codecId);
|
|
147
|
+
if (descriptor) validateTypeParams(column.typeParams, descriptor, {
|
|
148
|
+
tableName,
|
|
149
|
+
columnName
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Builds a registry of compiled JSON Schema validators by scanning the contract
|
|
155
|
+
* for columns whose codec descriptor provides an `init` hook returning `{ validate }`.
|
|
156
|
+
*
|
|
157
|
+
* Handles both:
|
|
158
|
+
* - Inline `typeParams.schema` on columns
|
|
159
|
+
* - `typeRef` → `storage.types[ref]` with init hook results already in `types` registry
|
|
160
|
+
*/
|
|
161
|
+
function buildJsonSchemaValidatorRegistry(contract, types, codecDescriptors) {
|
|
162
|
+
const validators = /* @__PURE__ */ new Map();
|
|
163
|
+
const codecIdsWithInit = /* @__PURE__ */ new Set();
|
|
164
|
+
for (const [codecId, descriptor] of codecDescriptors) if (descriptor.init) codecIdsWithInit.add(codecId);
|
|
165
|
+
if (codecIdsWithInit.size === 0) return;
|
|
166
|
+
for (const [tableName, table] of Object.entries(contract.storage.tables)) for (const [columnName, column] of Object.entries(table.columns)) {
|
|
167
|
+
if (!codecIdsWithInit.has(column.codecId)) continue;
|
|
168
|
+
const key = `${tableName}.${columnName}`;
|
|
169
|
+
if (column.typeRef) {
|
|
170
|
+
const helper = types[column.typeRef];
|
|
171
|
+
if (helper?.validate) validators.set(key, helper.validate);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (column.typeParams) {
|
|
175
|
+
const descriptor = codecDescriptors.get(column.codecId);
|
|
176
|
+
if (descriptor?.init) {
|
|
177
|
+
const helper = descriptor.init(column.typeParams);
|
|
178
|
+
if (helper?.validate) validators.set(key, helper.validate);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (validators.size === 0) return void 0;
|
|
183
|
+
return {
|
|
184
|
+
get: (key) => validators.get(key),
|
|
185
|
+
size: validators.size
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function computeExecutionDefaultValue(spec) {
|
|
189
|
+
switch (spec.kind) {
|
|
190
|
+
case "generator": return generateId(spec.params ? {
|
|
191
|
+
id: spec.id,
|
|
192
|
+
params: spec.params
|
|
193
|
+
} : { id: spec.id });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function applyMutationDefaults(contract, options) {
|
|
197
|
+
const defaults = contract.execution?.mutations.defaults ?? [];
|
|
198
|
+
if (defaults.length === 0) return [];
|
|
199
|
+
const applied = [];
|
|
200
|
+
const appliedColumns = /* @__PURE__ */ new Set();
|
|
201
|
+
for (const mutationDefault of defaults) {
|
|
202
|
+
if (mutationDefault.ref.table !== options.table) continue;
|
|
203
|
+
const defaultSpec = options.op === "create" ? mutationDefault.onCreate : mutationDefault.onUpdate;
|
|
204
|
+
if (!defaultSpec) continue;
|
|
205
|
+
const columnName = mutationDefault.ref.column;
|
|
206
|
+
if (Object.hasOwn(options.values, columnName) || appliedColumns.has(columnName)) continue;
|
|
207
|
+
applied.push({
|
|
208
|
+
column: columnName,
|
|
209
|
+
value: computeExecutionDefaultValue(defaultSpec)
|
|
210
|
+
});
|
|
211
|
+
appliedColumns.add(columnName);
|
|
212
|
+
}
|
|
213
|
+
return applied;
|
|
214
|
+
}
|
|
215
|
+
function createExecutionContext(options) {
|
|
216
|
+
const { contract, stack } = options;
|
|
217
|
+
assertExecutionStackContractRequirements(contract, stack);
|
|
218
|
+
const codecRegistry = createCodecRegistry();
|
|
219
|
+
const operationRegistry = createOperationRegistry();
|
|
220
|
+
const contributors = [
|
|
221
|
+
stack.target,
|
|
222
|
+
stack.adapter,
|
|
223
|
+
...stack.extensionPacks
|
|
224
|
+
];
|
|
225
|
+
for (const contributor of contributors) {
|
|
226
|
+
for (const c of contributor.codecs().values()) codecRegistry.register(c);
|
|
227
|
+
for (const operation of contributor.operationSignatures()) operationRegistry.register(operation);
|
|
228
|
+
}
|
|
229
|
+
const parameterizedCodecDescriptors = collectParameterizedCodecDescriptors(contributors);
|
|
230
|
+
if (parameterizedCodecDescriptors.size > 0) validateColumnTypeParams(contract.storage, parameterizedCodecDescriptors);
|
|
231
|
+
const types = initializeTypeHelpers(contract.storage.types, parameterizedCodecDescriptors);
|
|
232
|
+
const jsonSchemaValidators = buildJsonSchemaValidatorRegistry(contract, types, parameterizedCodecDescriptors);
|
|
233
|
+
return {
|
|
234
|
+
contract,
|
|
235
|
+
operations: operationRegistry,
|
|
236
|
+
codecs: codecRegistry,
|
|
237
|
+
types,
|
|
238
|
+
...jsonSchemaValidators ? { jsonSchemaValidators } : {},
|
|
239
|
+
applyMutationDefaults: (options$1) => applyMutationDefaults(contract, options$1)
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/sql-marker.ts
|
|
245
|
+
const ensureSchemaStatement = {
|
|
246
|
+
sql: "create schema if not exists prisma_contract",
|
|
247
|
+
params: []
|
|
248
|
+
};
|
|
249
|
+
const ensureTableStatement = {
|
|
250
|
+
sql: `create table if not exists prisma_contract.marker (
|
|
251
|
+
id smallint primary key default 1,
|
|
252
|
+
core_hash text not null,
|
|
253
|
+
profile_hash text not null,
|
|
254
|
+
contract_json jsonb,
|
|
255
|
+
canonical_version int,
|
|
256
|
+
updated_at timestamptz not null default now(),
|
|
257
|
+
app_tag text,
|
|
258
|
+
meta jsonb not null default '{}'
|
|
259
|
+
)`,
|
|
260
|
+
params: []
|
|
261
|
+
};
|
|
262
|
+
function readContractMarker() {
|
|
263
|
+
return {
|
|
264
|
+
sql: `select
|
|
265
|
+
core_hash,
|
|
266
|
+
profile_hash,
|
|
267
|
+
contract_json,
|
|
268
|
+
canonical_version,
|
|
269
|
+
updated_at,
|
|
270
|
+
app_tag,
|
|
271
|
+
meta
|
|
272
|
+
from prisma_contract.marker
|
|
273
|
+
where id = $1`,
|
|
274
|
+
params: [1]
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function writeContractMarker(input) {
|
|
278
|
+
const baseParams = [
|
|
279
|
+
1,
|
|
280
|
+
input.storageHash,
|
|
281
|
+
input.profileHash,
|
|
282
|
+
input.contractJson ?? null,
|
|
283
|
+
input.canonicalVersion ?? null,
|
|
284
|
+
input.appTag ?? null,
|
|
285
|
+
JSON.stringify(input.meta ?? {})
|
|
286
|
+
];
|
|
287
|
+
return {
|
|
288
|
+
insert: {
|
|
289
|
+
sql: `insert into prisma_contract.marker (
|
|
290
|
+
id,
|
|
291
|
+
core_hash,
|
|
292
|
+
profile_hash,
|
|
293
|
+
contract_json,
|
|
294
|
+
canonical_version,
|
|
295
|
+
updated_at,
|
|
296
|
+
app_tag,
|
|
297
|
+
meta
|
|
298
|
+
) values (
|
|
299
|
+
$1,
|
|
300
|
+
$2,
|
|
301
|
+
$3,
|
|
302
|
+
$4::jsonb,
|
|
303
|
+
$5,
|
|
304
|
+
now(),
|
|
305
|
+
$6,
|
|
306
|
+
$7::jsonb
|
|
307
|
+
)`,
|
|
308
|
+
params: baseParams
|
|
309
|
+
},
|
|
310
|
+
update: {
|
|
311
|
+
sql: `update prisma_contract.marker set
|
|
312
|
+
core_hash = $2,
|
|
313
|
+
profile_hash = $3,
|
|
314
|
+
contract_json = $4::jsonb,
|
|
315
|
+
canonical_version = $5,
|
|
316
|
+
updated_at = now(),
|
|
317
|
+
app_tag = $6,
|
|
318
|
+
meta = $7::jsonb
|
|
319
|
+
where id = $1`,
|
|
320
|
+
params: baseParams
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
//#endregion
|
|
326
|
+
//#region src/codecs/json-schema-validation.ts
|
|
327
|
+
/**
|
|
328
|
+
* Validates a JSON value against its column's JSON Schema, if a validator exists.
|
|
329
|
+
*
|
|
330
|
+
* Throws `RUNTIME.JSON_SCHEMA_VALIDATION_FAILED` on validation failure.
|
|
331
|
+
* No-ops if no validator is registered for the column.
|
|
332
|
+
*/
|
|
333
|
+
function validateJsonValue(registry, table, column, value, direction, codecId) {
|
|
334
|
+
const key = `${table}.${column}`;
|
|
335
|
+
const validate = registry.get(key);
|
|
336
|
+
if (!validate) return;
|
|
337
|
+
const result = validate(value);
|
|
338
|
+
if (result.valid) return;
|
|
339
|
+
throw createJsonSchemaValidationError(table, column, direction, result.errors, codecId);
|
|
340
|
+
}
|
|
341
|
+
function createJsonSchemaValidationError(table, column, direction, errors, codecId) {
|
|
342
|
+
return runtimeError("RUNTIME.JSON_SCHEMA_VALIDATION_FAILED", `JSON schema validation failed for column '${table}.${column}' (${direction}): ${formatErrorSummary(errors)}`, {
|
|
343
|
+
table,
|
|
344
|
+
column,
|
|
345
|
+
codecId,
|
|
346
|
+
direction,
|
|
347
|
+
errors: [...errors]
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
function formatErrorSummary(errors) {
|
|
351
|
+
if (errors.length === 0) return "unknown validation error";
|
|
352
|
+
if (errors.length === 1) {
|
|
353
|
+
const err = errors[0];
|
|
354
|
+
return err.path === "/" ? err.message : `${err.path}: ${err.message}`;
|
|
355
|
+
}
|
|
356
|
+
return errors.map((err) => err.path === "/" ? err.message : `${err.path}: ${err.message}`).join("; ");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/codecs/decoding.ts
|
|
361
|
+
function resolveRowCodec(alias, plan, registry) {
|
|
362
|
+
const planCodecId = plan.meta.annotations?.codecs?.[alias];
|
|
363
|
+
if (planCodecId) {
|
|
364
|
+
const codec$1 = registry.get(planCodecId);
|
|
365
|
+
if (codec$1) return codec$1;
|
|
366
|
+
}
|
|
367
|
+
if (plan.meta.projectionTypes) {
|
|
368
|
+
const typeId = plan.meta.projectionTypes[alias];
|
|
369
|
+
if (typeId) {
|
|
370
|
+
const codec$1 = registry.get(typeId);
|
|
371
|
+
if (codec$1) return codec$1;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Builds a lookup index from column name → { table, column } ref.
|
|
378
|
+
* Called once per decodeRow invocation to avoid O(aliases × refs) linear scans.
|
|
379
|
+
*/
|
|
380
|
+
function buildColumnRefIndex(plan) {
|
|
381
|
+
const columns = plan.meta.refs?.columns;
|
|
382
|
+
if (!columns) return null;
|
|
383
|
+
const index = /* @__PURE__ */ new Map();
|
|
384
|
+
for (const ref of columns) index.set(ref.column, ref);
|
|
385
|
+
return index;
|
|
386
|
+
}
|
|
387
|
+
function parseProjectionRef(value) {
|
|
388
|
+
if (value.startsWith("include:") || value.startsWith("operation:")) return null;
|
|
389
|
+
const separatorIndex = value.indexOf(".");
|
|
390
|
+
if (separatorIndex <= 0 || separatorIndex === value.length - 1) return null;
|
|
391
|
+
return {
|
|
392
|
+
table: value.slice(0, separatorIndex),
|
|
393
|
+
column: value.slice(separatorIndex + 1)
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function resolveColumnRefForAlias(alias, projection, fallbackColumnRefIndex) {
|
|
397
|
+
if (projection && !Array.isArray(projection)) {
|
|
398
|
+
const mappedRef = projection[alias];
|
|
399
|
+
if (typeof mappedRef !== "string") return;
|
|
400
|
+
return parseProjectionRef(mappedRef) ?? void 0;
|
|
401
|
+
}
|
|
402
|
+
return fallbackColumnRefIndex?.get(alias);
|
|
403
|
+
}
|
|
404
|
+
function decodeRow(row, plan, registry, jsonValidators) {
|
|
405
|
+
const decoded = {};
|
|
406
|
+
const projection = plan.meta.projection;
|
|
407
|
+
const fallbackColumnRefIndex = jsonValidators && (!projection || Array.isArray(projection)) ? buildColumnRefIndex(plan) : null;
|
|
408
|
+
let aliases;
|
|
409
|
+
if (projection && !Array.isArray(projection)) aliases = Object.keys(projection);
|
|
410
|
+
else if (projection && Array.isArray(projection)) aliases = projection;
|
|
411
|
+
else aliases = Object.keys(row);
|
|
412
|
+
for (const alias of aliases) {
|
|
413
|
+
const wireValue = row[alias];
|
|
414
|
+
const projectionValue = projection && typeof projection === "object" && !Array.isArray(projection) ? projection[alias] : void 0;
|
|
415
|
+
if (typeof projectionValue === "string" && projectionValue.startsWith("include:")) {
|
|
416
|
+
if (wireValue === null || wireValue === void 0) {
|
|
417
|
+
decoded[alias] = [];
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
try {
|
|
421
|
+
let parsed;
|
|
422
|
+
if (typeof wireValue === "string") parsed = JSON.parse(wireValue);
|
|
423
|
+
else if (Array.isArray(wireValue)) parsed = wireValue;
|
|
424
|
+
else parsed = JSON.parse(String(wireValue));
|
|
425
|
+
if (!Array.isArray(parsed)) throw new Error(`Expected array for include alias '${alias}', got ${typeof parsed}`);
|
|
426
|
+
decoded[alias] = parsed;
|
|
427
|
+
} catch (error) {
|
|
428
|
+
const decodeError = /* @__PURE__ */ new Error(`Failed to parse JSON array for include alias '${alias}': ${error instanceof Error ? error.message : String(error)}`);
|
|
429
|
+
decodeError.code = "RUNTIME.DECODE_FAILED";
|
|
430
|
+
decodeError.category = "RUNTIME";
|
|
431
|
+
decodeError.severity = "error";
|
|
432
|
+
decodeError.details = {
|
|
433
|
+
alias,
|
|
434
|
+
wirePreview: typeof wireValue === "string" && wireValue.length > 100 ? `${wireValue.substring(0, 100)}...` : String(wireValue).substring(0, 100)
|
|
435
|
+
};
|
|
436
|
+
throw decodeError;
|
|
437
|
+
}
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (wireValue === null || wireValue === void 0) {
|
|
441
|
+
decoded[alias] = wireValue;
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
const codec$1 = resolveRowCodec(alias, plan, registry);
|
|
445
|
+
if (!codec$1) {
|
|
446
|
+
decoded[alias] = wireValue;
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
try {
|
|
450
|
+
const decodedValue = codec$1.decode(wireValue);
|
|
451
|
+
if (jsonValidators) {
|
|
452
|
+
const ref = resolveColumnRefForAlias(alias, projection, fallbackColumnRefIndex);
|
|
453
|
+
if (ref) validateJsonValue(jsonValidators, ref.table, ref.column, decodedValue, "decode", codec$1.id);
|
|
454
|
+
}
|
|
455
|
+
decoded[alias] = decodedValue;
|
|
456
|
+
} catch (error) {
|
|
457
|
+
if (error instanceof Error && "code" in error && error.code === "RUNTIME.JSON_SCHEMA_VALIDATION_FAILED") throw error;
|
|
458
|
+
const decodeError = /* @__PURE__ */ new Error(`Failed to decode row alias '${alias}' with codec '${codec$1.id}': ${error instanceof Error ? error.message : String(error)}`);
|
|
459
|
+
decodeError.code = "RUNTIME.DECODE_FAILED";
|
|
460
|
+
decodeError.category = "RUNTIME";
|
|
461
|
+
decodeError.severity = "error";
|
|
462
|
+
decodeError.details = {
|
|
463
|
+
alias,
|
|
464
|
+
codec: codec$1.id,
|
|
465
|
+
wirePreview: typeof wireValue === "string" && wireValue.length > 100 ? `${wireValue.substring(0, 100)}...` : String(wireValue).substring(0, 100)
|
|
466
|
+
};
|
|
467
|
+
throw decodeError;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return decoded;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
//#endregion
|
|
474
|
+
//#region src/codecs/encoding.ts
|
|
475
|
+
function resolveParamCodec(paramDescriptor, plan, registry) {
|
|
476
|
+
const paramName = paramDescriptor.name ?? `param_${paramDescriptor.index ?? 0}`;
|
|
477
|
+
const planCodecId = plan.meta.annotations?.codecs?.[paramName];
|
|
478
|
+
if (planCodecId) {
|
|
479
|
+
const codec$1 = registry.get(planCodecId);
|
|
480
|
+
if (codec$1) return codec$1;
|
|
481
|
+
}
|
|
482
|
+
if (paramDescriptor.codecId) {
|
|
483
|
+
const codec$1 = registry.get(paramDescriptor.codecId);
|
|
484
|
+
if (codec$1) return codec$1;
|
|
485
|
+
}
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
function encodeParam(value, paramDescriptor, plan, registry, jsonValidators) {
|
|
489
|
+
if (value === null || value === void 0) return null;
|
|
490
|
+
if (jsonValidators && paramDescriptor.refs) {
|
|
491
|
+
const { table, column } = paramDescriptor.refs;
|
|
492
|
+
validateJsonValue(jsonValidators, table, column, value, "encode", paramDescriptor.codecId);
|
|
493
|
+
}
|
|
494
|
+
const codec$1 = resolveParamCodec(paramDescriptor, plan, registry);
|
|
495
|
+
if (!codec$1) return value;
|
|
496
|
+
if (codec$1.encode) try {
|
|
497
|
+
return codec$1.encode(value);
|
|
498
|
+
} catch (error) {
|
|
499
|
+
throw new Error(`Failed to encode parameter ${paramDescriptor.name ?? paramDescriptor.index}: ${error instanceof Error ? error.message : String(error)}`);
|
|
500
|
+
}
|
|
501
|
+
return value;
|
|
502
|
+
}
|
|
503
|
+
function encodeParams(plan, registry, jsonValidators) {
|
|
504
|
+
if (plan.params.length === 0) return plan.params;
|
|
505
|
+
const encoded = [];
|
|
506
|
+
for (let i = 0; i < plan.params.length; i++) {
|
|
507
|
+
const paramValue = plan.params[i];
|
|
508
|
+
const paramDescriptor = plan.meta.paramDescriptors[i];
|
|
509
|
+
if (paramDescriptor) encoded.push(encodeParam(paramValue, paramDescriptor, plan, registry, jsonValidators));
|
|
510
|
+
else encoded.push(paramValue);
|
|
511
|
+
}
|
|
512
|
+
return Object.freeze(encoded);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
//#endregion
|
|
516
|
+
//#region src/sql-family-adapter.ts
|
|
517
|
+
var SqlMarkerReader = class {
|
|
518
|
+
readMarkerStatement() {
|
|
519
|
+
return readContractMarker();
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
var SqlFamilyAdapter = class {
|
|
523
|
+
contract;
|
|
524
|
+
markerReader;
|
|
525
|
+
constructor(contract) {
|
|
526
|
+
this.contract = contract;
|
|
527
|
+
this.markerReader = new SqlMarkerReader();
|
|
528
|
+
}
|
|
529
|
+
validatePlan(plan, contract) {
|
|
530
|
+
if (plan.meta.target !== contract.target) throw runtimeError("PLAN.TARGET_MISMATCH", "Plan target does not match runtime target", {
|
|
531
|
+
planTarget: plan.meta.target,
|
|
532
|
+
runtimeTarget: contract.target
|
|
533
|
+
});
|
|
534
|
+
if (plan.meta.storageHash !== contract.storageHash) throw runtimeError("PLAN.HASH_MISMATCH", "Plan storage hash does not match runtime contract", {
|
|
535
|
+
planStorageHash: plan.meta.storageHash,
|
|
536
|
+
runtimeStorageHash: contract.storageHash
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
//#endregion
|
|
542
|
+
//#region src/sql-runtime.ts
|
|
543
|
+
var SqlRuntimeImpl = class {
|
|
544
|
+
core;
|
|
545
|
+
contract;
|
|
546
|
+
adapter;
|
|
547
|
+
codecRegistry;
|
|
548
|
+
jsonSchemaValidators;
|
|
549
|
+
codecRegistryValidated;
|
|
550
|
+
constructor(options) {
|
|
551
|
+
const { context, adapter, driver, verify, plugins, mode, log } = options;
|
|
552
|
+
this.contract = context.contract;
|
|
553
|
+
this.adapter = adapter;
|
|
554
|
+
this.codecRegistry = context.codecs;
|
|
555
|
+
this.jsonSchemaValidators = context.jsonSchemaValidators;
|
|
556
|
+
this.codecRegistryValidated = false;
|
|
557
|
+
this.core = createRuntimeCore({
|
|
558
|
+
familyAdapter: new SqlFamilyAdapter(context.contract),
|
|
559
|
+
driver,
|
|
560
|
+
verify,
|
|
561
|
+
plugins,
|
|
562
|
+
...ifDefined("mode", mode),
|
|
563
|
+
...ifDefined("log", log),
|
|
564
|
+
operationRegistry: context.operations
|
|
565
|
+
});
|
|
566
|
+
if (verify.mode === "startup") {
|
|
567
|
+
validateCodecRegistryCompleteness(this.codecRegistry, context.contract);
|
|
568
|
+
this.codecRegistryValidated = true;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
ensureCodecRegistryValidated(contract) {
|
|
572
|
+
if (!this.codecRegistryValidated) {
|
|
573
|
+
validateCodecRegistryCompleteness(this.codecRegistry, contract);
|
|
574
|
+
this.codecRegistryValidated = true;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
execute(plan) {
|
|
578
|
+
this.ensureCodecRegistryValidated(this.contract);
|
|
579
|
+
const isSqlQueryPlan = (p) => {
|
|
580
|
+
return "ast" in p && !("sql" in p);
|
|
581
|
+
};
|
|
582
|
+
const executablePlan = isSqlQueryPlan(plan) ? lowerSqlPlan(this.adapter, this.contract, plan) : plan;
|
|
583
|
+
const iterator = async function* (self) {
|
|
584
|
+
const encodedParams = encodeParams(executablePlan, self.codecRegistry, self.jsonSchemaValidators);
|
|
585
|
+
const planWithEncodedParams = {
|
|
586
|
+
...executablePlan,
|
|
587
|
+
params: encodedParams
|
|
588
|
+
};
|
|
589
|
+
const coreIterator = self.core.execute(planWithEncodedParams);
|
|
590
|
+
for await (const rawRow of coreIterator) yield decodeRow(rawRow, executablePlan, self.codecRegistry, self.jsonSchemaValidators);
|
|
591
|
+
};
|
|
592
|
+
return new AsyncIterableResult(iterator(this));
|
|
593
|
+
}
|
|
594
|
+
connection() {
|
|
595
|
+
return this.core.connection();
|
|
596
|
+
}
|
|
597
|
+
telemetry() {
|
|
598
|
+
return this.core.telemetry();
|
|
599
|
+
}
|
|
600
|
+
operations() {
|
|
601
|
+
return this.core.operations();
|
|
602
|
+
}
|
|
603
|
+
close() {
|
|
604
|
+
return this.core.close();
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
function createRuntime(options) {
|
|
608
|
+
const { stackInstance, context, driver, verify, plugins, mode, log } = options;
|
|
609
|
+
return new SqlRuntimeImpl({
|
|
610
|
+
context,
|
|
611
|
+
adapter: stackInstance.adapter,
|
|
612
|
+
driver,
|
|
613
|
+
verify,
|
|
614
|
+
...ifDefined("plugins", plugins),
|
|
615
|
+
...ifDefined("mode", mode),
|
|
616
|
+
...ifDefined("log", log)
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
//#endregion
|
|
621
|
+
export { ensureTableStatement as a, createExecutionContext as c, extractCodecIds as d, validateCodecRegistryCompleteness as f, ensureSchemaStatement as i, createSqlExecutionStack as l, lints as n, readContractMarker as o, validateContractCodecMappings as p, createRuntime as r, writeContractMarker as s, budgets as t, lowerSqlPlan as u };
|
|
622
|
+
//# sourceMappingURL=exports-C8hi0N-a.mjs.map
|