@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.
Files changed (144) hide show
  1. package/README.md +116 -26
  2. package/dist/exports-C8hi0N-a.mjs +622 -0
  3. package/dist/exports-C8hi0N-a.mjs.map +1 -0
  4. package/dist/index-SlQIrV_t.d.mts +131 -0
  5. package/dist/index-SlQIrV_t.d.mts.map +1 -0
  6. package/dist/index.d.mts +2 -0
  7. package/dist/index.mjs +3 -0
  8. package/dist/test/utils.d.mts +82 -0
  9. package/dist/test/utils.d.mts.map +1 -0
  10. package/dist/test/utils.mjs +212 -0
  11. package/dist/test/utils.mjs.map +1 -0
  12. package/package.json +35 -26
  13. package/src/codecs/decoding.ts +221 -0
  14. package/src/codecs/encoding.ts +89 -0
  15. package/src/codecs/json-schema-validation.ts +61 -0
  16. package/src/codecs/validation.ts +67 -0
  17. package/src/exports/index.ts +45 -0
  18. package/src/lower-sql-plan.ts +32 -0
  19. package/src/sql-context.ts +443 -0
  20. package/src/sql-family-adapter.ts +47 -0
  21. package/src/sql-marker.ts +105 -0
  22. package/src/sql-runtime.ts +232 -0
  23. package/test/async-iterable-result.test.ts +144 -0
  24. package/test/context.types.test-d.ts +68 -0
  25. package/test/execution-stack.test.ts +166 -0
  26. package/test/json-schema-validation.test.ts +653 -0
  27. package/test/parameterized-types.test.ts +539 -0
  28. package/test/sql-context.test.ts +392 -0
  29. package/test/sql-family-adapter.test.ts +87 -0
  30. package/test/sql-runtime.test.ts +241 -0
  31. package/test/utils.ts +291 -0
  32. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
  33. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
  34. package/dist/amcheck-24VY6X5V.js +0 -13
  35. package/dist/amcheck-24VY6X5V.js.map +0 -1
  36. package/dist/bloom-VS74NLHT.js +0 -13
  37. package/dist/bloom-VS74NLHT.js.map +0 -1
  38. package/dist/btree_gin-WBC4EAAI.js +0 -13
  39. package/dist/btree_gin-WBC4EAAI.js.map +0 -1
  40. package/dist/btree_gist-UNC6QD3M.js +0 -13
  41. package/dist/btree_gist-UNC6QD3M.js.map +0 -1
  42. package/dist/chunk-3KTOEDFX.js +0 -49
  43. package/dist/chunk-3KTOEDFX.js.map +0 -1
  44. package/dist/chunk-47DZBRQC.js +0 -1280
  45. package/dist/chunk-47DZBRQC.js.map +0 -1
  46. package/dist/chunk-52N6AFZM.js +0 -133
  47. package/dist/chunk-52N6AFZM.js.map +0 -1
  48. package/dist/chunk-7D4SUZUM.js +0 -38
  49. package/dist/chunk-7D4SUZUM.js.map +0 -1
  50. package/dist/chunk-C6I3V3DM.js +0 -455
  51. package/dist/chunk-C6I3V3DM.js.map +0 -1
  52. package/dist/chunk-ECWIHLAT.js +0 -37
  53. package/dist/chunk-ECWIHLAT.js.map +0 -1
  54. package/dist/chunk-EI626SDC.js +0 -105
  55. package/dist/chunk-EI626SDC.js.map +0 -1
  56. package/dist/chunk-UKKOYUGL.js +0 -578
  57. package/dist/chunk-UKKOYUGL.js.map +0 -1
  58. package/dist/chunk-XPLNMXQV.js +0 -1537
  59. package/dist/chunk-XPLNMXQV.js.map +0 -1
  60. package/dist/citext-T7MXGUY7.js +0 -13
  61. package/dist/citext-T7MXGUY7.js.map +0 -1
  62. package/dist/client-5FENX6AW.js +0 -299
  63. package/dist/client-5FENX6AW.js.map +0 -1
  64. package/dist/cube-TFDQBZCI.js +0 -13
  65. package/dist/cube-TFDQBZCI.js.map +0 -1
  66. package/dist/dict_int-AEUOPGWP.js +0 -13
  67. package/dist/dict_int-AEUOPGWP.js.map +0 -1
  68. package/dist/dict_xsyn-DAAYX3FL.js +0 -13
  69. package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
  70. package/dist/dist-AQ3LWXOX.js +0 -570
  71. package/dist/dist-AQ3LWXOX.js.map +0 -1
  72. package/dist/dist-LBVX6BJW.js +0 -189
  73. package/dist/dist-LBVX6BJW.js.map +0 -1
  74. package/dist/dist-WLKUVDN2.js +0 -5127
  75. package/dist/dist-WLKUVDN2.js.map +0 -1
  76. package/dist/earthdistance-KIGTF4LE.js +0 -13
  77. package/dist/earthdistance-KIGTF4LE.js.map +0 -1
  78. package/dist/file_fdw-5N55UP6I.js +0 -13
  79. package/dist/file_fdw-5N55UP6I.js.map +0 -1
  80. package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
  81. package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
  82. package/dist/hstore-YX726NKN.js +0 -13
  83. package/dist/hstore-YX726NKN.js.map +0 -1
  84. package/dist/http-exception-FZY2H4OF.js +0 -8
  85. package/dist/http-exception-FZY2H4OF.js.map +0 -1
  86. package/dist/index.d.ts +0 -29
  87. package/dist/index.js +0 -30
  88. package/dist/index.js.map +0 -1
  89. package/dist/intarray-NKVXNO2D.js +0 -13
  90. package/dist/intarray-NKVXNO2D.js.map +0 -1
  91. package/dist/isn-FTEMJGEV.js +0 -13
  92. package/dist/isn-FTEMJGEV.js.map +0 -1
  93. package/dist/lo-DB7L4NGI.js +0 -13
  94. package/dist/lo-DB7L4NGI.js.map +0 -1
  95. package/dist/logger-WQ7SHNDD.js +0 -68
  96. package/dist/logger-WQ7SHNDD.js.map +0 -1
  97. package/dist/ltree-Z32TZT6W.js +0 -13
  98. package/dist/ltree-Z32TZT6W.js.map +0 -1
  99. package/dist/nodefs-NM46ACH7.js +0 -31
  100. package/dist/nodefs-NM46ACH7.js.map +0 -1
  101. package/dist/opfs-ahp-NJO33LVZ.js +0 -332
  102. package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
  103. package/dist/pageinspect-YP3IZR4X.js +0 -13
  104. package/dist/pageinspect-YP3IZR4X.js.map +0 -1
  105. package/dist/pg_buffercache-7TD5J2FB.js +0 -13
  106. package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
  107. package/dist/pg_dump-SG4KYBUB.js +0 -2492
  108. package/dist/pg_dump-SG4KYBUB.js.map +0 -1
  109. package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
  110. package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
  111. package/dist/pg_surgery-J2MUEWEP.js +0 -13
  112. package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
  113. package/dist/pg_trgm-7VNQOYS6.js +0 -13
  114. package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
  115. package/dist/pg_visibility-TTSIPHFL.js +0 -13
  116. package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
  117. package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
  118. package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
  119. package/dist/proxy-signals-GUDAMDHV.js +0 -39
  120. package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
  121. package/dist/seg-IYVDLE4O.js +0 -13
  122. package/dist/seg-IYVDLE4O.js.map +0 -1
  123. package/dist/sql-runtime-DgEbg2OP.d.ts +0 -109
  124. package/dist/tablefunc-EF4RCS7S.js +0 -13
  125. package/dist/tablefunc-EF4RCS7S.js.map +0 -1
  126. package/dist/tcn-3VT5BQYW.js +0 -13
  127. package/dist/tcn-3VT5BQYW.js.map +0 -1
  128. package/dist/test/utils.d.ts +0 -64
  129. package/dist/test/utils.js +0 -24634
  130. package/dist/test/utils.js.map +0 -1
  131. package/dist/tiny-CW6F4GX6.js +0 -10
  132. package/dist/tiny-CW6F4GX6.js.map +0 -1
  133. package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
  134. package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
  135. package/dist/tsm_system_time-76WEIMBG.js +0 -13
  136. package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
  137. package/dist/unaccent-7RYF3R64.js +0 -13
  138. package/dist/unaccent-7RYF3R64.js.map +0 -1
  139. package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
  140. package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
  141. package/dist/uuid_ossp-4ETE4FPE.js +0 -13
  142. package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
  143. package/dist/vector-74GPNV7V.js +0 -13
  144. package/dist/vector-74GPNV7V.js.map +0 -1
@@ -0,0 +1,443 @@
1
+ import { checkContractComponentRequirements } from '@prisma-next/contract/framework-components';
2
+ import type { ExecutionMutationDefaultValue } from '@prisma-next/contract/types';
3
+ import { createExecutionStack, type ExecutionStack } from '@prisma-next/core-execution-plane/stack';
4
+ import type {
5
+ RuntimeAdapterDescriptor,
6
+ RuntimeAdapterInstance,
7
+ RuntimeDriverDescriptor,
8
+ RuntimeDriverInstance,
9
+ RuntimeExtensionDescriptor,
10
+ RuntimeExtensionInstance,
11
+ RuntimeTargetDescriptor,
12
+ RuntimeTargetInstance,
13
+ } from '@prisma-next/core-execution-plane/types';
14
+ import { generateId } from '@prisma-next/ids/runtime';
15
+ import { createOperationRegistry } from '@prisma-next/operations';
16
+ import { runtimeError } from '@prisma-next/runtime-executor';
17
+ import type { SqlContract, SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
18
+ import type { SqlOperationSignature } from '@prisma-next/sql-operations';
19
+ import type {
20
+ Adapter,
21
+ CodecParamsDescriptor,
22
+ CodecRegistry,
23
+ LoweredStatement,
24
+ QueryAst,
25
+ SqlDriver,
26
+ } from '@prisma-next/sql-relational-core/ast';
27
+ import { createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
28
+ import type {
29
+ AppliedMutationDefault,
30
+ ExecutionContext,
31
+ JsonSchemaValidateFn,
32
+ JsonSchemaValidatorRegistry,
33
+ MutationDefaultsOptions,
34
+ TypeHelperRegistry,
35
+ } from '@prisma-next/sql-relational-core/query-lane-context';
36
+ import { type as arktype } from 'arktype';
37
+
38
+ /**
39
+ * Runtime parameterized codec descriptor.
40
+ * Provides validation schema and optional init hook for codecs that support type parameters.
41
+ * Used at runtime to validate typeParams and create type helpers.
42
+ *
43
+ * This is a type alias for `CodecParamsDescriptor` from the AST layer,
44
+ * which is the shared definition used by both adapter and runtime.
45
+ */
46
+ export type RuntimeParameterizedCodecDescriptor<
47
+ TParams = Record<string, unknown>,
48
+ THelper = unknown,
49
+ > = CodecParamsDescriptor<TParams, THelper>;
50
+
51
+ export interface SqlStaticContributions {
52
+ readonly codecs: () => CodecRegistry;
53
+ readonly operationSignatures: () => ReadonlyArray<SqlOperationSignature>;
54
+ // biome-ignore lint/suspicious/noExplicitAny: needed for covariance with concrete descriptor types
55
+ readonly parameterizedCodecs: () => ReadonlyArray<RuntimeParameterizedCodecDescriptor<any, any>>;
56
+ }
57
+
58
+ export interface SqlRuntimeTargetDescriptor<
59
+ TTargetId extends string = string,
60
+ TTargetInstance extends RuntimeTargetInstance<'sql', TTargetId> = RuntimeTargetInstance<
61
+ 'sql',
62
+ TTargetId
63
+ >,
64
+ > extends RuntimeTargetDescriptor<'sql', TTargetId, TTargetInstance>,
65
+ SqlStaticContributions {}
66
+
67
+ export interface SqlRuntimeAdapterDescriptor<
68
+ TTargetId extends string = string,
69
+ TAdapterInstance extends RuntimeAdapterInstance<
70
+ 'sql',
71
+ TTargetId
72
+ > = SqlRuntimeAdapterInstance<TTargetId>,
73
+ > extends RuntimeAdapterDescriptor<'sql', TTargetId, TAdapterInstance>,
74
+ SqlStaticContributions {}
75
+
76
+ export interface SqlRuntimeExtensionDescriptor<TTargetId extends string = string>
77
+ extends RuntimeExtensionDescriptor<'sql', TTargetId, SqlRuntimeExtensionInstance<TTargetId>>,
78
+ SqlStaticContributions {
79
+ create(): SqlRuntimeExtensionInstance<TTargetId>;
80
+ }
81
+
82
+ export interface SqlExecutionStack<TTargetId extends string = string> {
83
+ readonly target: SqlRuntimeTargetDescriptor<TTargetId>;
84
+ readonly adapter: SqlRuntimeAdapterDescriptor<TTargetId>;
85
+ readonly extensionPacks: readonly SqlRuntimeExtensionDescriptor<TTargetId>[];
86
+ }
87
+
88
+ export type SqlExecutionStackWithDriver<TTargetId extends string = string> = Omit<
89
+ ExecutionStack<
90
+ 'sql',
91
+ TTargetId,
92
+ SqlRuntimeAdapterInstance<TTargetId>,
93
+ SqlRuntimeDriverInstance<TTargetId>,
94
+ SqlRuntimeExtensionInstance<TTargetId>
95
+ >,
96
+ 'target' | 'adapter' | 'driver' | 'extensionPacks'
97
+ > & {
98
+ readonly target: SqlRuntimeTargetDescriptor<TTargetId>;
99
+ readonly adapter: SqlRuntimeAdapterDescriptor<TTargetId, SqlRuntimeAdapterInstance<TTargetId>>;
100
+ readonly driver:
101
+ | RuntimeDriverDescriptor<'sql', TTargetId, unknown, SqlRuntimeDriverInstance<TTargetId>>
102
+ | undefined;
103
+ readonly extensionPacks: readonly SqlRuntimeExtensionDescriptor<TTargetId>[];
104
+ };
105
+
106
+ export interface SqlRuntimeExtensionInstance<TTargetId extends string>
107
+ extends RuntimeExtensionInstance<'sql', TTargetId> {}
108
+
109
+ export type SqlRuntimeAdapterInstance<TTargetId extends string = string> = RuntimeAdapterInstance<
110
+ 'sql',
111
+ TTargetId
112
+ > &
113
+ Adapter<QueryAst, SqlContract<SqlStorage>, LoweredStatement>;
114
+
115
+ /**
116
+ * NOTE: Binding type is intentionally erased to unknown at this shared runtime layer.
117
+ * Target clients (for example `postgres()`) validate and construct the concrete binding
118
+ * before calling `driver.connect(binding)`, which keeps runtime behavior safe today.
119
+ * A future follow-up can preserve TBinding through stack/context generics end-to-end.
120
+ */
121
+ export type SqlRuntimeDriverInstance<TTargetId extends string = string> = RuntimeDriverInstance<
122
+ 'sql',
123
+ TTargetId
124
+ > &
125
+ SqlDriver<unknown>;
126
+
127
+ export function createSqlExecutionStack<TTargetId extends string>(options: {
128
+ readonly target: SqlRuntimeTargetDescriptor<TTargetId>;
129
+ readonly adapter: SqlRuntimeAdapterDescriptor<TTargetId>;
130
+ readonly driver?:
131
+ | RuntimeDriverDescriptor<'sql', TTargetId, unknown, SqlRuntimeDriverInstance<TTargetId>>
132
+ | undefined;
133
+ readonly extensionPacks?: readonly SqlRuntimeExtensionDescriptor<TTargetId>[] | undefined;
134
+ }): SqlExecutionStackWithDriver<TTargetId> {
135
+ return createExecutionStack({
136
+ target: options.target,
137
+ adapter: options.adapter,
138
+ driver: options.driver,
139
+ extensionPacks: options.extensionPacks,
140
+ });
141
+ }
142
+
143
+ export type { ExecutionContext, JsonSchemaValidatorRegistry, TypeHelperRegistry };
144
+
145
+ export function assertExecutionStackContractRequirements(
146
+ contract: SqlContract<SqlStorage>,
147
+ stack: SqlExecutionStack,
148
+ ): void {
149
+ const providedComponentIds = new Set<string>([
150
+ stack.target.id,
151
+ stack.adapter.id,
152
+ ...stack.extensionPacks.map((pack) => pack.id),
153
+ ]);
154
+
155
+ const result = checkContractComponentRequirements({
156
+ contract,
157
+ expectedTargetFamily: 'sql',
158
+ expectedTargetId: stack.target.targetId,
159
+ providedComponentIds,
160
+ });
161
+
162
+ if (result.familyMismatch) {
163
+ throw runtimeError(
164
+ 'RUNTIME.CONTRACT_FAMILY_MISMATCH',
165
+ `Contract target family '${result.familyMismatch.actual}' does not match runtime family '${result.familyMismatch.expected}'.`,
166
+ {
167
+ actual: result.familyMismatch.actual,
168
+ expected: result.familyMismatch.expected,
169
+ },
170
+ );
171
+ }
172
+
173
+ if (result.targetMismatch) {
174
+ throw runtimeError(
175
+ 'RUNTIME.CONTRACT_TARGET_MISMATCH',
176
+ `Contract target '${result.targetMismatch.actual}' does not match runtime target descriptor '${result.targetMismatch.expected}'.`,
177
+ {
178
+ actual: result.targetMismatch.actual,
179
+ expected: result.targetMismatch.expected,
180
+ },
181
+ );
182
+ }
183
+
184
+ if (result.missingExtensionPackIds.length > 0) {
185
+ const packIds = result.missingExtensionPackIds;
186
+ const packList = packIds.map((id) => `'${id}'`).join(', ');
187
+ throw runtimeError(
188
+ 'RUNTIME.MISSING_EXTENSION_PACK',
189
+ `Contract requires extension pack(s) ${packList}, but runtime descriptors do not provide matching component(s).`,
190
+ { packIds },
191
+ );
192
+ }
193
+ }
194
+
195
+ function validateTypeParams(
196
+ typeParams: Record<string, unknown>,
197
+ codecDescriptor: RuntimeParameterizedCodecDescriptor,
198
+ context: { typeName?: string; tableName?: string; columnName?: string },
199
+ ): Record<string, unknown> {
200
+ const result = codecDescriptor.paramsSchema(typeParams);
201
+ if (result instanceof arktype.errors) {
202
+ const messages = result.map((p: { message: string }) => p.message).join('; ');
203
+ const locationInfo = context.typeName
204
+ ? `type '${context.typeName}'`
205
+ : `column '${context.tableName}.${context.columnName}'`;
206
+ throw runtimeError(
207
+ 'RUNTIME.TYPE_PARAMS_INVALID',
208
+ `Invalid typeParams for ${locationInfo} (codecId: ${codecDescriptor.codecId}): ${messages}`,
209
+ { ...context, codecId: codecDescriptor.codecId, typeParams },
210
+ );
211
+ }
212
+ return result as Record<string, unknown>;
213
+ }
214
+
215
+ function collectParameterizedCodecDescriptors(
216
+ contributors: ReadonlyArray<SqlStaticContributions>,
217
+ ): Map<string, RuntimeParameterizedCodecDescriptor> {
218
+ const descriptors = new Map<string, RuntimeParameterizedCodecDescriptor>();
219
+
220
+ for (const contributor of contributors) {
221
+ for (const descriptor of contributor.parameterizedCodecs()) {
222
+ if (descriptors.has(descriptor.codecId)) {
223
+ throw runtimeError(
224
+ 'RUNTIME.DUPLICATE_PARAMETERIZED_CODEC',
225
+ `Duplicate parameterized codec descriptor for codecId '${descriptor.codecId}'.`,
226
+ { codecId: descriptor.codecId },
227
+ );
228
+ }
229
+ descriptors.set(descriptor.codecId, descriptor);
230
+ }
231
+ }
232
+
233
+ return descriptors;
234
+ }
235
+
236
+ function initializeTypeHelpers(
237
+ storageTypes: Record<string, StorageTypeInstance> | undefined,
238
+ codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
239
+ ): TypeHelperRegistry {
240
+ const helpers: TypeHelperRegistry = {};
241
+
242
+ if (!storageTypes) {
243
+ return helpers;
244
+ }
245
+
246
+ for (const [typeName, typeInstance] of Object.entries(storageTypes)) {
247
+ const descriptor = codecDescriptors.get(typeInstance.codecId);
248
+
249
+ if (descriptor) {
250
+ const validatedParams = validateTypeParams(typeInstance.typeParams, descriptor, {
251
+ typeName,
252
+ });
253
+
254
+ if (descriptor.init) {
255
+ helpers[typeName] = descriptor.init(validatedParams);
256
+ } else {
257
+ helpers[typeName] = typeInstance;
258
+ }
259
+ } else {
260
+ helpers[typeName] = typeInstance;
261
+ }
262
+ }
263
+
264
+ return helpers;
265
+ }
266
+
267
+ function validateColumnTypeParams(
268
+ storage: SqlStorage,
269
+ codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
270
+ ): void {
271
+ for (const [tableName, table] of Object.entries(storage.tables)) {
272
+ for (const [columnName, column] of Object.entries(table.columns)) {
273
+ if (column.typeParams) {
274
+ const descriptor = codecDescriptors.get(column.codecId);
275
+ if (descriptor) {
276
+ validateTypeParams(column.typeParams, descriptor, { tableName, columnName });
277
+ }
278
+ }
279
+ }
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Builds a registry of compiled JSON Schema validators by scanning the contract
285
+ * for columns whose codec descriptor provides an `init` hook returning `{ validate }`.
286
+ *
287
+ * Handles both:
288
+ * - Inline `typeParams.schema` on columns
289
+ * - `typeRef` → `storage.types[ref]` with init hook results already in `types` registry
290
+ */
291
+ function buildJsonSchemaValidatorRegistry(
292
+ contract: SqlContract<SqlStorage>,
293
+ types: TypeHelperRegistry,
294
+ codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
295
+ ): JsonSchemaValidatorRegistry | undefined {
296
+ const validators = new Map<string, JsonSchemaValidateFn>();
297
+
298
+ // Collect codec IDs that have init hooks (these produce { validate } helpers)
299
+ const codecIdsWithInit = new Set<string>();
300
+ for (const [codecId, descriptor] of codecDescriptors) {
301
+ if (descriptor.init) {
302
+ codecIdsWithInit.add(codecId);
303
+ }
304
+ }
305
+
306
+ if (codecIdsWithInit.size === 0) {
307
+ return undefined;
308
+ }
309
+
310
+ for (const [tableName, table] of Object.entries(contract.storage.tables)) {
311
+ for (const [columnName, column] of Object.entries(table.columns)) {
312
+ if (!codecIdsWithInit.has(column.codecId)) continue;
313
+
314
+ const key = `${tableName}.${columnName}`;
315
+
316
+ // Case 1: column references a named type → validator already compiled via init hook
317
+ if (column.typeRef) {
318
+ const helper = types[column.typeRef] as { validate?: JsonSchemaValidateFn } | undefined;
319
+ if (helper?.validate) {
320
+ validators.set(key, helper.validate);
321
+ }
322
+ continue;
323
+ }
324
+
325
+ // Case 2: inline typeParams with schema → compile via init hook
326
+ if (column.typeParams) {
327
+ const descriptor = codecDescriptors.get(column.codecId);
328
+ if (descriptor?.init) {
329
+ const helper = descriptor.init(column.typeParams) as
330
+ | { validate?: JsonSchemaValidateFn }
331
+ | undefined;
332
+ if (helper?.validate) {
333
+ validators.set(key, helper.validate);
334
+ }
335
+ }
336
+ }
337
+ }
338
+ }
339
+
340
+ if (validators.size === 0) return undefined;
341
+ return {
342
+ get: (key: string) => validators.get(key),
343
+ size: validators.size,
344
+ };
345
+ }
346
+
347
+ function computeExecutionDefaultValue(spec: ExecutionMutationDefaultValue): unknown {
348
+ switch (spec.kind) {
349
+ case 'generator':
350
+ return generateId(spec.params ? { id: spec.id, params: spec.params } : { id: spec.id });
351
+ }
352
+ }
353
+
354
+ function applyMutationDefaults(
355
+ contract: SqlContract<SqlStorage>,
356
+ options: MutationDefaultsOptions,
357
+ ): ReadonlyArray<AppliedMutationDefault> {
358
+ const defaults = contract.execution?.mutations.defaults ?? [];
359
+ if (defaults.length === 0) {
360
+ return [];
361
+ }
362
+
363
+ const applied: AppliedMutationDefault[] = [];
364
+ const appliedColumns = new Set<string>();
365
+
366
+ for (const mutationDefault of defaults) {
367
+ if (mutationDefault.ref.table !== options.table) {
368
+ continue;
369
+ }
370
+
371
+ const defaultSpec =
372
+ options.op === 'create' ? mutationDefault.onCreate : mutationDefault.onUpdate;
373
+ if (!defaultSpec) {
374
+ continue;
375
+ }
376
+
377
+ const columnName = mutationDefault.ref.column;
378
+ if (Object.hasOwn(options.values, columnName) || appliedColumns.has(columnName)) {
379
+ continue;
380
+ }
381
+
382
+ applied.push({
383
+ column: columnName,
384
+ value: computeExecutionDefaultValue(defaultSpec),
385
+ });
386
+ appliedColumns.add(columnName);
387
+ }
388
+
389
+ return applied;
390
+ }
391
+
392
+ export function createExecutionContext<
393
+ TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
394
+ TTargetId extends string = string,
395
+ >(options: {
396
+ readonly contract: TContract;
397
+ readonly stack: SqlExecutionStack<TTargetId>;
398
+ }): ExecutionContext<TContract> {
399
+ const { contract, stack } = options;
400
+
401
+ assertExecutionStackContractRequirements(contract, stack);
402
+
403
+ const codecRegistry = createCodecRegistry();
404
+ const operationRegistry = createOperationRegistry();
405
+
406
+ const contributors: SqlStaticContributions[] = [
407
+ stack.target,
408
+ stack.adapter,
409
+ ...stack.extensionPacks,
410
+ ];
411
+
412
+ for (const contributor of contributors) {
413
+ for (const c of contributor.codecs().values()) {
414
+ codecRegistry.register(c);
415
+ }
416
+ for (const operation of contributor.operationSignatures()) {
417
+ operationRegistry.register(operation);
418
+ }
419
+ }
420
+
421
+ const parameterizedCodecDescriptors = collectParameterizedCodecDescriptors(contributors);
422
+
423
+ if (parameterizedCodecDescriptors.size > 0) {
424
+ validateColumnTypeParams(contract.storage, parameterizedCodecDescriptors);
425
+ }
426
+
427
+ const types = initializeTypeHelpers(contract.storage.types, parameterizedCodecDescriptors);
428
+
429
+ const jsonSchemaValidators = buildJsonSchemaValidatorRegistry(
430
+ contract,
431
+ types,
432
+ parameterizedCodecDescriptors,
433
+ );
434
+
435
+ return {
436
+ contract,
437
+ operations: operationRegistry,
438
+ codecs: codecRegistry,
439
+ types,
440
+ ...(jsonSchemaValidators ? { jsonSchemaValidators } : {}),
441
+ applyMutationDefaults: (options) => applyMutationDefaults(contract, options),
442
+ };
443
+ }
@@ -0,0 +1,47 @@
1
+ import type { ExecutionPlan } from '@prisma-next/contract/types';
2
+ import type {
3
+ MarkerReader,
4
+ MarkerStatement,
5
+ RuntimeFamilyAdapter,
6
+ } from '@prisma-next/runtime-executor';
7
+ import { runtimeError } from '@prisma-next/runtime-executor';
8
+ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
9
+ import { readContractMarker } from './sql-marker';
10
+
11
+ class SqlMarkerReader implements MarkerReader {
12
+ readMarkerStatement(): MarkerStatement {
13
+ return readContractMarker();
14
+ }
15
+ }
16
+
17
+ export class SqlFamilyAdapter<TContract extends SqlContract<SqlStorage>>
18
+ implements RuntimeFamilyAdapter<TContract>
19
+ {
20
+ readonly contract: TContract;
21
+ readonly markerReader: MarkerReader;
22
+
23
+ constructor(contract: TContract) {
24
+ this.contract = contract;
25
+ this.markerReader = new SqlMarkerReader();
26
+ }
27
+
28
+ validatePlan(plan: ExecutionPlan, contract: TContract): void {
29
+ if (plan.meta.target !== contract.target) {
30
+ throw runtimeError('PLAN.TARGET_MISMATCH', 'Plan target does not match runtime target', {
31
+ planTarget: plan.meta.target,
32
+ runtimeTarget: contract.target,
33
+ });
34
+ }
35
+
36
+ if (plan.meta.storageHash !== contract.storageHash) {
37
+ throw runtimeError(
38
+ 'PLAN.HASH_MISMATCH',
39
+ 'Plan storage hash does not match runtime contract',
40
+ {
41
+ planStorageHash: plan.meta.storageHash,
42
+ runtimeStorageHash: contract.storageHash,
43
+ },
44
+ );
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,105 @@
1
+ import type { MarkerStatement } from '@prisma-next/runtime-executor';
2
+
3
+ export interface SqlStatement {
4
+ readonly sql: string;
5
+ readonly params: readonly unknown[];
6
+ }
7
+
8
+ export interface WriteMarkerInput {
9
+ readonly storageHash: string;
10
+ readonly profileHash: string;
11
+ readonly contractJson?: unknown;
12
+ readonly canonicalVersion?: number;
13
+ readonly appTag?: string;
14
+ readonly meta?: Record<string, unknown>;
15
+ }
16
+
17
+ export const ensureSchemaStatement: SqlStatement = {
18
+ sql: 'create schema if not exists prisma_contract',
19
+ params: [],
20
+ };
21
+
22
+ export const ensureTableStatement: SqlStatement = {
23
+ sql: `create table if not exists prisma_contract.marker (
24
+ id smallint primary key default 1,
25
+ core_hash text not null,
26
+ profile_hash text not null,
27
+ contract_json jsonb,
28
+ canonical_version int,
29
+ updated_at timestamptz not null default now(),
30
+ app_tag text,
31
+ meta jsonb not null default '{}'
32
+ )`,
33
+ params: [],
34
+ };
35
+
36
+ export function readContractMarker(): MarkerStatement {
37
+ return {
38
+ sql: `select
39
+ core_hash,
40
+ profile_hash,
41
+ contract_json,
42
+ canonical_version,
43
+ updated_at,
44
+ app_tag,
45
+ meta
46
+ from prisma_contract.marker
47
+ where id = $1`,
48
+ params: [1],
49
+ };
50
+ }
51
+
52
+ export interface WriteContractMarkerStatements {
53
+ readonly insert: SqlStatement;
54
+ readonly update: SqlStatement;
55
+ }
56
+
57
+ export function writeContractMarker(input: WriteMarkerInput): WriteContractMarkerStatements {
58
+ const baseParams: readonly unknown[] = [
59
+ 1,
60
+ input.storageHash,
61
+ input.profileHash,
62
+ input.contractJson ?? null,
63
+ input.canonicalVersion ?? null,
64
+ input.appTag ?? null,
65
+ JSON.stringify(input.meta ?? {}),
66
+ ];
67
+
68
+ const insert: SqlStatement = {
69
+ sql: `insert into prisma_contract.marker (
70
+ id,
71
+ core_hash,
72
+ profile_hash,
73
+ contract_json,
74
+ canonical_version,
75
+ updated_at,
76
+ app_tag,
77
+ meta
78
+ ) values (
79
+ $1,
80
+ $2,
81
+ $3,
82
+ $4::jsonb,
83
+ $5,
84
+ now(),
85
+ $6,
86
+ $7::jsonb
87
+ )`,
88
+ params: baseParams,
89
+ };
90
+
91
+ const update: SqlStatement = {
92
+ sql: `update prisma_contract.marker set
93
+ core_hash = $2,
94
+ profile_hash = $3,
95
+ contract_json = $4::jsonb,
96
+ canonical_version = $5,
97
+ updated_at = now(),
98
+ app_tag = $6,
99
+ meta = $7::jsonb
100
+ where id = $1`,
101
+ params: baseParams,
102
+ };
103
+
104
+ return { insert, update };
105
+ }