@prisma-next/sql-runtime 0.3.0-dev.16 → 0.3.0-dev.163

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