@prisma-next/sql-runtime 0.3.0-dev.14 → 0.3.0-dev.146

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 (170) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +141 -24
  3. package/dist/exports-DGa0ipuP.mjs +956 -0
  4. package/dist/exports-DGa0ipuP.mjs.map +1 -0
  5. package/dist/index-CDbmlDcn.d.mts +177 -0
  6. package/dist/index-CDbmlDcn.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 +6 -5
  18. package/src/exports/index.ts +19 -7
  19. package/src/lower-sql-plan.ts +9 -9
  20. package/src/plugins/budgets.ts +375 -0
  21. package/src/plugins/lints.ts +211 -0
  22. package/src/sql-context.ts +454 -108
  23. package/src/sql-family-adapter.ts +16 -22
  24. package/src/sql-marker.ts +2 -2
  25. package/src/sql-runtime.ts +136 -47
  26. package/test/async-iterable-result.test.ts +42 -37
  27. package/test/budgets.test.ts +481 -0
  28. package/test/context.types.test-d.ts +68 -0
  29. package/test/execution-stack.test.ts +164 -0
  30. package/test/json-schema-validation.test.ts +571 -0
  31. package/test/lints.test.ts +161 -0
  32. package/test/mutation-default-generators.test.ts +254 -0
  33. package/test/parameterized-types.test.ts +529 -0
  34. package/test/sql-context.test.ts +301 -134
  35. package/test/sql-family-adapter.test.ts +37 -20
  36. package/test/sql-runtime.test.ts +220 -49
  37. package/test/utils.ts +101 -67
  38. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
  39. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
  40. package/dist/amcheck-24VY6X5V.js +0 -13
  41. package/dist/amcheck-24VY6X5V.js.map +0 -1
  42. package/dist/bloom-VS74NLHT.js +0 -13
  43. package/dist/bloom-VS74NLHT.js.map +0 -1
  44. package/dist/btree_gin-WBC4EAAI.js +0 -13
  45. package/dist/btree_gin-WBC4EAAI.js.map +0 -1
  46. package/dist/btree_gist-UNC6QD3M.js +0 -13
  47. package/dist/btree_gist-UNC6QD3M.js.map +0 -1
  48. package/dist/chunk-3KTOEDFX.js +0 -49
  49. package/dist/chunk-3KTOEDFX.js.map +0 -1
  50. package/dist/chunk-47DZBRQC.js +0 -1280
  51. package/dist/chunk-47DZBRQC.js.map +0 -1
  52. package/dist/chunk-52N6AFZM.js +0 -133
  53. package/dist/chunk-52N6AFZM.js.map +0 -1
  54. package/dist/chunk-7D4SUZUM.js +0 -38
  55. package/dist/chunk-7D4SUZUM.js.map +0 -1
  56. package/dist/chunk-C6I3V3DM.js +0 -455
  57. package/dist/chunk-C6I3V3DM.js.map +0 -1
  58. package/dist/chunk-ECWIHLAT.js +0 -37
  59. package/dist/chunk-ECWIHLAT.js.map +0 -1
  60. package/dist/chunk-EI626SDC.js +0 -105
  61. package/dist/chunk-EI626SDC.js.map +0 -1
  62. package/dist/chunk-UKKOYUGL.js +0 -578
  63. package/dist/chunk-UKKOYUGL.js.map +0 -1
  64. package/dist/chunk-XPLNMXQV.js +0 -1537
  65. package/dist/chunk-XPLNMXQV.js.map +0 -1
  66. package/dist/citext-T7MXGUY7.js +0 -13
  67. package/dist/citext-T7MXGUY7.js.map +0 -1
  68. package/dist/client-5FENX6AW.js +0 -299
  69. package/dist/client-5FENX6AW.js.map +0 -1
  70. package/dist/cube-TFDQBZCI.js +0 -13
  71. package/dist/cube-TFDQBZCI.js.map +0 -1
  72. package/dist/dict_int-AEUOPGWP.js +0 -13
  73. package/dist/dict_int-AEUOPGWP.js.map +0 -1
  74. package/dist/dict_xsyn-DAAYX3FL.js +0 -13
  75. package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
  76. package/dist/dist-AQ3LWXOX.js +0 -570
  77. package/dist/dist-AQ3LWXOX.js.map +0 -1
  78. package/dist/dist-LBVX6BJW.js +0 -189
  79. package/dist/dist-LBVX6BJW.js.map +0 -1
  80. package/dist/dist-WLKUVDN2.js +0 -5127
  81. package/dist/dist-WLKUVDN2.js.map +0 -1
  82. package/dist/earthdistance-KIGTF4LE.js +0 -13
  83. package/dist/earthdistance-KIGTF4LE.js.map +0 -1
  84. package/dist/file_fdw-5N55UP6I.js +0 -13
  85. package/dist/file_fdw-5N55UP6I.js.map +0 -1
  86. package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
  87. package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
  88. package/dist/hstore-YX726NKN.js +0 -13
  89. package/dist/hstore-YX726NKN.js.map +0 -1
  90. package/dist/http-exception-FZY2H4OF.js +0 -8
  91. package/dist/http-exception-FZY2H4OF.js.map +0 -1
  92. package/dist/index.js +0 -30
  93. package/dist/index.js.map +0 -1
  94. package/dist/intarray-NKVXNO2D.js +0 -13
  95. package/dist/intarray-NKVXNO2D.js.map +0 -1
  96. package/dist/isn-FTEMJGEV.js +0 -13
  97. package/dist/isn-FTEMJGEV.js.map +0 -1
  98. package/dist/lo-DB7L4NGI.js +0 -13
  99. package/dist/lo-DB7L4NGI.js.map +0 -1
  100. package/dist/logger-WQ7SHNDD.js +0 -68
  101. package/dist/logger-WQ7SHNDD.js.map +0 -1
  102. package/dist/ltree-Z32TZT6W.js +0 -13
  103. package/dist/ltree-Z32TZT6W.js.map +0 -1
  104. package/dist/nodefs-NM46ACH7.js +0 -31
  105. package/dist/nodefs-NM46ACH7.js.map +0 -1
  106. package/dist/opfs-ahp-NJO33LVZ.js +0 -332
  107. package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
  108. package/dist/pageinspect-YP3IZR4X.js +0 -13
  109. package/dist/pageinspect-YP3IZR4X.js.map +0 -1
  110. package/dist/pg_buffercache-7TD5J2FB.js +0 -13
  111. package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
  112. package/dist/pg_dump-SG4KYBUB.js +0 -2492
  113. package/dist/pg_dump-SG4KYBUB.js.map +0 -1
  114. package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
  115. package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
  116. package/dist/pg_surgery-J2MUEWEP.js +0 -13
  117. package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
  118. package/dist/pg_trgm-7VNQOYS6.js +0 -13
  119. package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
  120. package/dist/pg_visibility-TTSIPHFL.js +0 -13
  121. package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
  122. package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
  123. package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
  124. package/dist/proxy-signals-GUDAMDHV.js +0 -39
  125. package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
  126. package/dist/seg-IYVDLE4O.js +0 -13
  127. package/dist/seg-IYVDLE4O.js.map +0 -1
  128. package/dist/src/codecs/decoding.d.ts +0 -4
  129. package/dist/src/codecs/decoding.d.ts.map +0 -1
  130. package/dist/src/codecs/encoding.d.ts +0 -5
  131. package/dist/src/codecs/encoding.d.ts.map +0 -1
  132. package/dist/src/codecs/validation.d.ts +0 -6
  133. package/dist/src/codecs/validation.d.ts.map +0 -1
  134. package/dist/src/exports/index.d.ts +0 -11
  135. package/dist/src/exports/index.d.ts.map +0 -1
  136. package/dist/src/index.d.ts +0 -2
  137. package/dist/src/index.d.ts.map +0 -1
  138. package/dist/src/lower-sql-plan.d.ts +0 -15
  139. package/dist/src/lower-sql-plan.d.ts.map +0 -1
  140. package/dist/src/sql-context.d.ts +0 -65
  141. package/dist/src/sql-context.d.ts.map +0 -1
  142. package/dist/src/sql-family-adapter.d.ts +0 -10
  143. package/dist/src/sql-family-adapter.d.ts.map +0 -1
  144. package/dist/src/sql-marker.d.ts +0 -22
  145. package/dist/src/sql-marker.d.ts.map +0 -1
  146. package/dist/src/sql-runtime.d.ts +0 -25
  147. package/dist/src/sql-runtime.d.ts.map +0 -1
  148. package/dist/tablefunc-EF4RCS7S.js +0 -13
  149. package/dist/tablefunc-EF4RCS7S.js.map +0 -1
  150. package/dist/tcn-3VT5BQYW.js +0 -13
  151. package/dist/tcn-3VT5BQYW.js.map +0 -1
  152. package/dist/test/utils.d.ts +0 -60
  153. package/dist/test/utils.d.ts.map +0 -1
  154. package/dist/test/utils.js +0 -24635
  155. package/dist/test/utils.js.map +0 -1
  156. package/dist/tiny-CW6F4GX6.js +0 -10
  157. package/dist/tiny-CW6F4GX6.js.map +0 -1
  158. package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
  159. package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
  160. package/dist/tsm_system_time-76WEIMBG.js +0 -13
  161. package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
  162. package/dist/unaccent-7RYF3R64.js +0 -13
  163. package/dist/unaccent-7RYF3R64.js.map +0 -1
  164. package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
  165. package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
  166. package/dist/uuid_ossp-4ETE4FPE.js +0 -13
  167. package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
  168. package/dist/vector-74GPNV7V.js +0 -13
  169. package/dist/vector-74GPNV7V.js.map +0 -1
  170. package/src/index.ts +0 -1
@@ -0,0 +1,956 @@
1
+ import { AsyncIterableResult, createRuntimeCore, evaluateRawGuardrails, runtimeError } from "@prisma-next/runtime-executor";
2
+ import { createCodecRegistry, isQueryAst } from "@prisma-next/sql-relational-core/ast";
3
+ import { ifDefined } from "@prisma-next/utils/defined";
4
+ import { checkContractComponentRequirements } from "@prisma-next/framework-components/components";
5
+ import { createExecutionStack } from "@prisma-next/framework-components/execution";
6
+ import { createSqlOperationRegistry } from "@prisma-next/sql-operations";
7
+ import { type } from "arktype";
8
+
9
+ //#region src/codecs/validation.ts
10
+ function extractCodecIds(contract) {
11
+ const codecIds = /* @__PURE__ */ new Set();
12
+ for (const table of Object.values(contract.storage.tables)) for (const column of Object.values(table.columns)) {
13
+ const codecId = column.codecId;
14
+ codecIds.add(codecId);
15
+ }
16
+ return codecIds;
17
+ }
18
+ function extractCodecIdsFromColumns(contract) {
19
+ const codecIds = /* @__PURE__ */ new Map();
20
+ for (const [tableName, table] of Object.entries(contract.storage.tables)) for (const [columnName, column] of Object.entries(table.columns)) {
21
+ const codecId = column.codecId;
22
+ const key = `${tableName}.${columnName}`;
23
+ codecIds.set(key, codecId);
24
+ }
25
+ return codecIds;
26
+ }
27
+ function validateContractCodecMappings(registry, contract) {
28
+ const codecIds = extractCodecIdsFromColumns(contract);
29
+ const invalidCodecs = [];
30
+ for (const [key, codecId] of codecIds.entries()) if (!registry.has(codecId)) {
31
+ const parts = key.split(".");
32
+ const table = parts[0] ?? "";
33
+ const column = parts[1] ?? "";
34
+ invalidCodecs.push({
35
+ table,
36
+ column,
37
+ codecId
38
+ });
39
+ }
40
+ if (invalidCodecs.length > 0) {
41
+ const details = {
42
+ contractTarget: contract.target,
43
+ invalidCodecs
44
+ };
45
+ throw runtimeError("RUNTIME.CODEC_MISSING", `Missing codec implementations for column codecIds: ${invalidCodecs.map((c) => `${c.table}.${c.column} (${c.codecId})`).join(", ")}`, details);
46
+ }
47
+ }
48
+ function validateCodecRegistryCompleteness(registry, contract) {
49
+ validateContractCodecMappings(registry, contract);
50
+ }
51
+
52
+ //#endregion
53
+ //#region src/lower-sql-plan.ts
54
+ /**
55
+ * Lowers a SQL query plan to an executable Plan by calling the adapter's lower method.
56
+ *
57
+ * @param adapter - Adapter to lower AST to SQL
58
+ * @param contract - Contract for lowering context
59
+ * @param queryPlan - SQL query plan from a lane (contains AST, params, meta, but no SQL)
60
+ * @returns Fully executable Plan with SQL string
61
+ */
62
+ function lowerSqlPlan(adapter, contract, queryPlan) {
63
+ const body = adapter.lower(queryPlan.ast, {
64
+ contract,
65
+ params: queryPlan.params
66
+ }).body;
67
+ return Object.freeze({
68
+ sql: body.sql,
69
+ params: body.params ?? queryPlan.params,
70
+ ast: queryPlan.ast,
71
+ meta: queryPlan.meta
72
+ });
73
+ }
74
+
75
+ //#endregion
76
+ //#region src/plugins/budgets.ts
77
+ async function computeEstimatedRows(plan, driver) {
78
+ if (typeof driver.explain !== "function") return;
79
+ try {
80
+ return extractEstimatedRows((await driver.explain({
81
+ sql: plan.sql,
82
+ params: plan.params
83
+ })).rows);
84
+ } catch {
85
+ return;
86
+ }
87
+ }
88
+ function extractEstimatedRows(rows) {
89
+ for (const row of rows) {
90
+ const estimate = findPlanRows(row);
91
+ if (estimate !== void 0) return estimate;
92
+ }
93
+ }
94
+ function findPlanRows(node) {
95
+ if (!node || typeof node !== "object") return;
96
+ const explainNode = node;
97
+ const planRows = explainNode["Plan Rows"];
98
+ if (typeof planRows === "number") return planRows;
99
+ if ("Plan" in explainNode && explainNode.Plan !== void 0) {
100
+ const nested = findPlanRows(explainNode.Plan);
101
+ if (nested !== void 0) return nested;
102
+ }
103
+ if (Array.isArray(explainNode.Plans)) for (const child of explainNode.Plans) {
104
+ const nested = findPlanRows(child);
105
+ if (nested !== void 0) return nested;
106
+ }
107
+ for (const value of Object.values(node)) if (typeof value === "object" && value !== null) {
108
+ const nested = findPlanRows(value);
109
+ if (nested !== void 0) return nested;
110
+ }
111
+ }
112
+ function budgetError(code, message, details) {
113
+ const error = new Error(message);
114
+ Object.defineProperty(error, "name", {
115
+ value: "RuntimeError",
116
+ configurable: true
117
+ });
118
+ return Object.assign(error, {
119
+ code,
120
+ category: "BUDGET",
121
+ severity: "error",
122
+ details
123
+ });
124
+ }
125
+ function hasAggregateWithoutGroupBy(ast) {
126
+ if (ast.groupBy !== void 0) return false;
127
+ return ast.projection.some((item) => item.expr.kind === "aggregate");
128
+ }
129
+ function estimateRowsFromAst(ast, tableRows, defaultTableRows, refs, hasAggregateWithoutGroup) {
130
+ if (hasAggregateWithoutGroup) return 1;
131
+ const table = refs?.tables?.[0];
132
+ if (!table) return null;
133
+ const tableEstimate = tableRows[table] ?? defaultTableRows;
134
+ if (ast.limit !== void 0) return Math.min(ast.limit, tableEstimate);
135
+ return tableEstimate;
136
+ }
137
+ function estimateRowsFromHeuristics(plan, tableRows, defaultTableRows) {
138
+ const table = plan.meta.refs?.tables?.[0];
139
+ if (!table) return null;
140
+ const tableEstimate = tableRows[table] ?? defaultTableRows;
141
+ const limit = plan.meta.annotations?.["limit"];
142
+ if (typeof limit === "number") return Math.min(limit, tableEstimate);
143
+ return tableEstimate;
144
+ }
145
+ function hasDetectableLimitFromHeuristics(plan) {
146
+ return typeof plan.meta.annotations?.["limit"] === "number";
147
+ }
148
+ function emitBudgetViolation(error, shouldBlock, ctx) {
149
+ if (shouldBlock) throw error;
150
+ ctx.log.warn({
151
+ code: error.code,
152
+ message: error.message,
153
+ details: error.details
154
+ });
155
+ }
156
+ function budgets(options) {
157
+ const maxRows = options?.maxRows ?? 1e4;
158
+ const defaultTableRows = options?.defaultTableRows ?? 1e4;
159
+ const tableRows = options?.tableRows ?? {};
160
+ const maxLatencyMs = options?.maxLatencyMs ?? 1e3;
161
+ const rowSeverity = options?.severities?.rowCount ?? "error";
162
+ const observedRowsByPlan = /* @__PURE__ */ new WeakMap();
163
+ return Object.freeze({
164
+ name: "budgets",
165
+ async beforeExecute(plan, ctx) {
166
+ observedRowsByPlan.set(plan, { count: 0 });
167
+ if (isQueryAst(plan.ast)) {
168
+ if (plan.ast.kind === "select") return evaluateSelectAst(plan, plan.ast, ctx);
169
+ return;
170
+ }
171
+ return evaluateWithHeuristics(plan, ctx);
172
+ },
173
+ async onRow(_row, plan, _ctx) {
174
+ const state = observedRowsByPlan.get(plan);
175
+ if (!state) return;
176
+ state.count += 1;
177
+ if (state.count > maxRows) throw budgetError("BUDGET.ROWS_EXCEEDED", "Observed row count exceeds budget", {
178
+ source: "observed",
179
+ observedRows: state.count,
180
+ maxRows
181
+ });
182
+ },
183
+ async afterExecute(_plan, result, ctx) {
184
+ const latencyMs = result.latencyMs;
185
+ if (latencyMs > maxLatencyMs) {
186
+ const shouldBlock = ctx.mode === "strict";
187
+ emitBudgetViolation(budgetError("BUDGET.TIME_EXCEEDED", "Query latency exceeds budget", {
188
+ latencyMs,
189
+ maxLatencyMs
190
+ }), shouldBlock, ctx);
191
+ }
192
+ }
193
+ });
194
+ function evaluateSelectAst(plan, ast, ctx) {
195
+ const hasAggNoGroup = hasAggregateWithoutGroupBy(ast);
196
+ const estimated = estimateRowsFromAst(ast, tableRows, defaultTableRows, plan.meta.refs, hasAggNoGroup);
197
+ const isUnbounded = ast.limit === void 0 && !hasAggNoGroup;
198
+ const shouldBlock = rowSeverity === "error" || ctx.mode === "strict";
199
+ if (isUnbounded) {
200
+ if (estimated !== null && estimated >= maxRows) {
201
+ emitBudgetViolation(budgetError("BUDGET.ROWS_EXCEEDED", "Unbounded SELECT query exceeds budget", {
202
+ source: "ast",
203
+ estimatedRows: estimated,
204
+ maxRows
205
+ }), shouldBlock, ctx);
206
+ return;
207
+ }
208
+ emitBudgetViolation(budgetError("BUDGET.ROWS_EXCEEDED", "Unbounded SELECT query exceeds budget", {
209
+ source: "ast",
210
+ maxRows
211
+ }), shouldBlock, ctx);
212
+ return;
213
+ }
214
+ if (estimated !== null && estimated > maxRows) emitBudgetViolation(budgetError("BUDGET.ROWS_EXCEEDED", "Estimated row count exceeds budget", {
215
+ source: "ast",
216
+ estimatedRows: estimated,
217
+ maxRows
218
+ }), shouldBlock, ctx);
219
+ }
220
+ async function evaluateWithHeuristics(plan, ctx) {
221
+ const estimated = estimateRowsFromHeuristics(plan, tableRows, defaultTableRows);
222
+ const isUnbounded = !hasDetectableLimitFromHeuristics(plan);
223
+ const isSelect = plan.sql.trimStart().toUpperCase().startsWith("SELECT");
224
+ const shouldBlock = rowSeverity === "error" || ctx.mode === "strict";
225
+ if (isSelect && isUnbounded) {
226
+ if (estimated !== null && estimated >= maxRows) {
227
+ emitBudgetViolation(budgetError("BUDGET.ROWS_EXCEEDED", "Unbounded SELECT query exceeds budget", {
228
+ source: "heuristic",
229
+ estimatedRows: estimated,
230
+ maxRows
231
+ }), shouldBlock, ctx);
232
+ return;
233
+ }
234
+ emitBudgetViolation(budgetError("BUDGET.ROWS_EXCEEDED", "Unbounded SELECT query exceeds budget", {
235
+ source: "heuristic",
236
+ maxRows
237
+ }), shouldBlock, ctx);
238
+ return;
239
+ }
240
+ if (estimated !== null) {
241
+ if (estimated > maxRows) emitBudgetViolation(budgetError("BUDGET.ROWS_EXCEEDED", "Estimated row count exceeds budget", {
242
+ source: "heuristic",
243
+ estimatedRows: estimated,
244
+ maxRows
245
+ }), shouldBlock, ctx);
246
+ return;
247
+ }
248
+ if (options?.explain?.enabled === true && isSelect && typeof ctx.driver === "object" && ctx.driver !== null) {
249
+ const estimatedRows = await computeEstimatedRows(plan, ctx.driver);
250
+ if (estimatedRows !== void 0) {
251
+ if (estimatedRows > maxRows) emitBudgetViolation(budgetError("BUDGET.ROWS_EXCEEDED", "Estimated row count exceeds budget", {
252
+ source: "explain",
253
+ estimatedRows,
254
+ maxRows
255
+ }), shouldBlock, ctx);
256
+ }
257
+ }
258
+ }
259
+ }
260
+
261
+ //#endregion
262
+ //#region src/plugins/lints.ts
263
+ function lintError(code, message, details) {
264
+ const error = new Error(message);
265
+ Object.defineProperty(error, "name", {
266
+ value: "RuntimeError",
267
+ configurable: true
268
+ });
269
+ return Object.assign(error, {
270
+ code,
271
+ category: "LINT",
272
+ severity: "error",
273
+ details
274
+ });
275
+ }
276
+ function getFromSourceTableDetail(source) {
277
+ switch (source.kind) {
278
+ case "table-source": return source.name;
279
+ case "derived-table-source": return source.alias;
280
+ default: throw new Error(`Unsupported source kind: ${source.kind}`);
281
+ }
282
+ }
283
+ function evaluateAstLints(ast) {
284
+ const findings = [];
285
+ switch (ast.kind) {
286
+ case "delete":
287
+ if (ast.where === void 0) findings.push({
288
+ code: "LINT.DELETE_WITHOUT_WHERE",
289
+ severity: "error",
290
+ message: "DELETE without WHERE clause blocks execution to prevent accidental full-table deletion",
291
+ details: { table: ast.table.name }
292
+ });
293
+ break;
294
+ case "update":
295
+ if (ast.where === void 0) findings.push({
296
+ code: "LINT.UPDATE_WITHOUT_WHERE",
297
+ severity: "error",
298
+ message: "UPDATE without WHERE clause blocks execution to prevent accidental full-table update",
299
+ details: { table: ast.table.name }
300
+ });
301
+ break;
302
+ case "select":
303
+ if (ast.limit === void 0) {
304
+ const table = getFromSourceTableDetail(ast.from);
305
+ findings.push({
306
+ code: "LINT.NO_LIMIT",
307
+ severity: "warn",
308
+ message: "Unbounded SELECT may return large result sets",
309
+ ...ifDefined("details", table !== void 0 ? { table } : void 0)
310
+ });
311
+ }
312
+ if (ast.selectAllIntent !== void 0) {
313
+ const table = ast.selectAllIntent.table;
314
+ findings.push({
315
+ code: "LINT.SELECT_STAR",
316
+ severity: "warn",
317
+ message: "Query selects all columns via selectAll intent",
318
+ ...ifDefined("details", table !== void 0 ? { table } : void 0)
319
+ });
320
+ }
321
+ break;
322
+ case "insert": break;
323
+ default: throw new Error(`Unsupported AST kind: ${ast.kind}`);
324
+ }
325
+ return findings;
326
+ }
327
+ function getConfiguredSeverity(code, options) {
328
+ const severities = options?.severities;
329
+ if (!severities) return void 0;
330
+ switch (code) {
331
+ case "LINT.SELECT_STAR": return severities.selectStar;
332
+ case "LINT.NO_LIMIT": return severities.noLimit;
333
+ case "LINT.DELETE_WITHOUT_WHERE": return severities.deleteWithoutWhere;
334
+ case "LINT.UPDATE_WITHOUT_WHERE": return severities.updateWithoutWhere;
335
+ case "LINT.READ_ONLY_MUTATION": return severities.readOnlyMutation;
336
+ case "LINT.UNINDEXED_PREDICATE": return severities.unindexedPredicate;
337
+ default: return;
338
+ }
339
+ }
340
+ /**
341
+ * AST-first lint plugin for SQL plans. When `plan.ast` is a SQL QueryAst, inspects
342
+ * the AST structurally. When `plan.ast` is missing, falls back to raw heuristic
343
+ * guardrails or skips linting depending on `fallbackWhenAstMissing`.
344
+ *
345
+ * Rules (AST-based):
346
+ * - DELETE without WHERE: blocks execution (configurable severity, default error)
347
+ * - UPDATE without WHERE: blocks execution (configurable severity, default error)
348
+ * - Unbounded SELECT: warn/error (severity from noLimit)
349
+ * - SELECT * intent: warn/error (severity from selectStar)
350
+ *
351
+ * Fallback: When ast is missing, `fallbackWhenAstMissing: 'raw'` uses heuristic
352
+ * SQL parsing; `'skip'` skips all lints. Default is `'raw'`.
353
+ */
354
+ function lints(options) {
355
+ const fallback = options?.fallbackWhenAstMissing ?? "raw";
356
+ return Object.freeze({
357
+ name: "lints",
358
+ async beforeExecute(plan, ctx) {
359
+ if (isQueryAst(plan.ast)) {
360
+ const findings = evaluateAstLints(plan.ast);
361
+ for (const lint of findings) {
362
+ const effectiveSeverity = getConfiguredSeverity(lint.code, options) ?? lint.severity;
363
+ if (effectiveSeverity === "error") throw lintError(lint.code, lint.message, lint.details);
364
+ if (effectiveSeverity === "warn") ctx.log.warn({
365
+ code: lint.code,
366
+ message: lint.message,
367
+ details: lint.details
368
+ });
369
+ }
370
+ return;
371
+ }
372
+ if (fallback === "skip") return;
373
+ const evaluation = evaluateRawGuardrails(plan);
374
+ for (const lint of evaluation.lints) {
375
+ const effectiveSeverity = getConfiguredSeverity(lint.code, options) ?? lint.severity;
376
+ if (effectiveSeverity === "error") throw lintError(lint.code, lint.message, lint.details);
377
+ if (effectiveSeverity === "warn") ctx.log.warn({
378
+ code: lint.code,
379
+ message: lint.message,
380
+ details: lint.details
381
+ });
382
+ }
383
+ }
384
+ });
385
+ }
386
+
387
+ //#endregion
388
+ //#region src/sql-context.ts
389
+ function createSqlExecutionStack(options) {
390
+ return createExecutionStack({
391
+ target: options.target,
392
+ adapter: options.adapter,
393
+ driver: options.driver,
394
+ extensionPacks: options.extensionPacks
395
+ });
396
+ }
397
+ function assertExecutionStackContractRequirements(contract, stack) {
398
+ const providedComponentIds = new Set([
399
+ stack.target.id,
400
+ stack.adapter.id,
401
+ ...stack.extensionPacks.map((pack) => pack.id)
402
+ ]);
403
+ const result = checkContractComponentRequirements({
404
+ contract,
405
+ expectedTargetFamily: "sql",
406
+ expectedTargetId: stack.target.targetId,
407
+ providedComponentIds
408
+ });
409
+ if (result.familyMismatch) throw runtimeError("RUNTIME.CONTRACT_FAMILY_MISMATCH", `Contract target family '${result.familyMismatch.actual}' does not match runtime family '${result.familyMismatch.expected}'.`, {
410
+ actual: result.familyMismatch.actual,
411
+ expected: result.familyMismatch.expected
412
+ });
413
+ if (result.targetMismatch) throw runtimeError("RUNTIME.CONTRACT_TARGET_MISMATCH", `Contract target '${result.targetMismatch.actual}' does not match runtime target descriptor '${result.targetMismatch.expected}'.`, {
414
+ actual: result.targetMismatch.actual,
415
+ expected: result.targetMismatch.expected
416
+ });
417
+ if (result.missingExtensionPackIds.length > 0) {
418
+ const packIds = result.missingExtensionPackIds;
419
+ 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 });
420
+ }
421
+ }
422
+ function validateTypeParams(typeParams, codecDescriptor, context) {
423
+ const result = codecDescriptor.paramsSchema(typeParams);
424
+ if (result instanceof type.errors) {
425
+ const messages = result.map((p) => p.message).join("; ");
426
+ throw runtimeError("RUNTIME.TYPE_PARAMS_INVALID", `Invalid typeParams for ${context.typeName ? `type '${context.typeName}'` : `column '${context.tableName}.${context.columnName}'`} (codecId: ${codecDescriptor.codecId}): ${messages}`, {
427
+ ...context,
428
+ codecId: codecDescriptor.codecId,
429
+ typeParams
430
+ });
431
+ }
432
+ return result;
433
+ }
434
+ function collectParameterizedCodecDescriptors(contributors) {
435
+ const descriptors = /* @__PURE__ */ new Map();
436
+ for (const contributor of contributors) for (const descriptor of contributor.parameterizedCodecs()) {
437
+ if (descriptors.has(descriptor.codecId)) throw runtimeError("RUNTIME.DUPLICATE_PARAMETERIZED_CODEC", `Duplicate parameterized codec descriptor for codecId '${descriptor.codecId}'.`, { codecId: descriptor.codecId });
438
+ descriptors.set(descriptor.codecId, descriptor);
439
+ }
440
+ return descriptors;
441
+ }
442
+ function initializeTypeHelpers(storageTypes, codecDescriptors) {
443
+ const helpers = {};
444
+ if (!storageTypes) return helpers;
445
+ for (const [typeName, typeInstance] of Object.entries(storageTypes)) {
446
+ const descriptor = codecDescriptors.get(typeInstance.codecId);
447
+ if (descriptor) {
448
+ const validatedParams = validateTypeParams(typeInstance.typeParams, descriptor, { typeName });
449
+ if (descriptor.init) helpers[typeName] = descriptor.init(validatedParams);
450
+ else helpers[typeName] = typeInstance;
451
+ } else helpers[typeName] = typeInstance;
452
+ }
453
+ return helpers;
454
+ }
455
+ function validateColumnTypeParams(storage, codecDescriptors) {
456
+ for (const [tableName, table] of Object.entries(storage.tables)) for (const [columnName, column] of Object.entries(table.columns)) if (column.typeParams) {
457
+ const descriptor = codecDescriptors.get(column.codecId);
458
+ if (descriptor) validateTypeParams(column.typeParams, descriptor, {
459
+ tableName,
460
+ columnName
461
+ });
462
+ }
463
+ }
464
+ /**
465
+ * Builds a registry of compiled JSON Schema validators by scanning the contract
466
+ * for columns whose codec descriptor provides an `init` hook returning `{ validate }`.
467
+ *
468
+ * Handles both:
469
+ * - Inline `typeParams.schema` on columns
470
+ * - `typeRef` → `storage.types[ref]` with init hook results already in `types` registry
471
+ */
472
+ function buildJsonSchemaValidatorRegistry(contract, types, codecDescriptors) {
473
+ const validators = /* @__PURE__ */ new Map();
474
+ const codecIdsWithInit = /* @__PURE__ */ new Set();
475
+ for (const [codecId, descriptor] of codecDescriptors) if (descriptor.init) codecIdsWithInit.add(codecId);
476
+ if (codecIdsWithInit.size === 0) return;
477
+ for (const [tableName, table] of Object.entries(contract.storage.tables)) for (const [columnName, column] of Object.entries(table.columns)) {
478
+ if (!codecIdsWithInit.has(column.codecId)) continue;
479
+ const key = `${tableName}.${columnName}`;
480
+ if (column.typeRef) {
481
+ const helper = types[column.typeRef];
482
+ if (helper?.validate) validators.set(key, helper.validate);
483
+ continue;
484
+ }
485
+ if (column.typeParams) {
486
+ const descriptor = codecDescriptors.get(column.codecId);
487
+ if (descriptor?.init) {
488
+ const helper = descriptor.init(column.typeParams);
489
+ if (helper?.validate) validators.set(key, helper.validate);
490
+ }
491
+ }
492
+ }
493
+ if (validators.size === 0) return void 0;
494
+ return {
495
+ get: (key) => validators.get(key),
496
+ size: validators.size
497
+ };
498
+ }
499
+ function collectMutationDefaultGenerators(contributors) {
500
+ const generators = /* @__PURE__ */ new Map();
501
+ const owners = /* @__PURE__ */ new Map();
502
+ for (const contributor of contributors) {
503
+ const nextGenerators = contributor.mutationDefaultGenerators?.() ?? [];
504
+ for (const generator of nextGenerators) {
505
+ const existingOwner = owners.get(generator.id);
506
+ if (existingOwner !== void 0) throw runtimeError("RUNTIME.DUPLICATE_MUTATION_DEFAULT_GENERATOR", `Duplicate mutation default generator '${generator.id}'.`, {
507
+ id: generator.id,
508
+ existingOwner,
509
+ incomingOwner: contributor.id
510
+ });
511
+ generators.set(generator.id, generator);
512
+ owners.set(generator.id, contributor.id);
513
+ }
514
+ }
515
+ return generators;
516
+ }
517
+ function computeExecutionDefaultValue(spec, generatorRegistry) {
518
+ switch (spec.kind) {
519
+ case "generator": {
520
+ const generator = generatorRegistry.get(spec.id);
521
+ if (!generator) throw runtimeError("RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING", `Contract references mutation default generator '${spec.id}' but no runtime component provides it.`, { id: spec.id });
522
+ return generator.generate(spec.params);
523
+ }
524
+ }
525
+ }
526
+ function applyMutationDefaults(contract, generatorRegistry, options) {
527
+ const defaults = contract.execution?.mutations.defaults ?? [];
528
+ if (defaults.length === 0) return [];
529
+ const applied = [];
530
+ const appliedColumns = /* @__PURE__ */ new Set();
531
+ for (const mutationDefault of defaults) {
532
+ if (mutationDefault.ref.table !== options.table) continue;
533
+ const defaultSpec = options.op === "create" ? mutationDefault.onCreate : mutationDefault.onUpdate;
534
+ if (!defaultSpec) continue;
535
+ const columnName = mutationDefault.ref.column;
536
+ if (Object.hasOwn(options.values, columnName) || appliedColumns.has(columnName)) continue;
537
+ applied.push({
538
+ column: columnName,
539
+ value: computeExecutionDefaultValue(defaultSpec, generatorRegistry)
540
+ });
541
+ appliedColumns.add(columnName);
542
+ }
543
+ return applied;
544
+ }
545
+ function createExecutionContext(options) {
546
+ const { contract, stack } = options;
547
+ assertExecutionStackContractRequirements(contract, stack);
548
+ const codecRegistry = createCodecRegistry();
549
+ const contributors = [
550
+ stack.target,
551
+ stack.adapter,
552
+ ...stack.extensionPacks
553
+ ];
554
+ for (const contributor of contributors) for (const c of contributor.codecs().values()) codecRegistry.register(c);
555
+ const queryOperationRegistry = createSqlOperationRegistry();
556
+ for (const contributor of contributors) for (const op of contributor.queryOperations?.() ?? []) queryOperationRegistry.register(op);
557
+ const parameterizedCodecDescriptors = collectParameterizedCodecDescriptors(contributors);
558
+ const mutationDefaultGeneratorRegistry = collectMutationDefaultGenerators(contributors);
559
+ if (parameterizedCodecDescriptors.size > 0) validateColumnTypeParams(contract.storage, parameterizedCodecDescriptors);
560
+ const types = initializeTypeHelpers(contract.storage.types, parameterizedCodecDescriptors);
561
+ const jsonSchemaValidators = buildJsonSchemaValidatorRegistry(contract, types, parameterizedCodecDescriptors);
562
+ return {
563
+ contract,
564
+ codecs: codecRegistry,
565
+ queryOperations: queryOperationRegistry,
566
+ types,
567
+ ...jsonSchemaValidators ? { jsonSchemaValidators } : {},
568
+ applyMutationDefaults: (options$1) => applyMutationDefaults(contract, mutationDefaultGeneratorRegistry, options$1)
569
+ };
570
+ }
571
+
572
+ //#endregion
573
+ //#region src/sql-marker.ts
574
+ const ensureSchemaStatement = {
575
+ sql: "create schema if not exists prisma_contract",
576
+ params: []
577
+ };
578
+ const ensureTableStatement = {
579
+ sql: `create table if not exists prisma_contract.marker (
580
+ id smallint primary key default 1,
581
+ core_hash text not null,
582
+ profile_hash text not null,
583
+ contract_json jsonb,
584
+ canonical_version int,
585
+ updated_at timestamptz not null default now(),
586
+ app_tag text,
587
+ meta jsonb not null default '{}'
588
+ )`,
589
+ params: []
590
+ };
591
+ function readContractMarker() {
592
+ return {
593
+ sql: `select
594
+ core_hash,
595
+ profile_hash,
596
+ contract_json,
597
+ canonical_version,
598
+ updated_at,
599
+ app_tag,
600
+ meta
601
+ from prisma_contract.marker
602
+ where id = $1`,
603
+ params: [1]
604
+ };
605
+ }
606
+ function writeContractMarker(input) {
607
+ const baseParams = [
608
+ 1,
609
+ input.storageHash,
610
+ input.profileHash,
611
+ input.contractJson ?? null,
612
+ input.canonicalVersion ?? null,
613
+ input.appTag ?? null,
614
+ JSON.stringify(input.meta ?? {})
615
+ ];
616
+ return {
617
+ insert: {
618
+ sql: `insert into prisma_contract.marker (
619
+ id,
620
+ core_hash,
621
+ profile_hash,
622
+ contract_json,
623
+ canonical_version,
624
+ updated_at,
625
+ app_tag,
626
+ meta
627
+ ) values (
628
+ $1,
629
+ $2,
630
+ $3,
631
+ $4::jsonb,
632
+ $5,
633
+ now(),
634
+ $6,
635
+ $7::jsonb
636
+ )`,
637
+ params: baseParams
638
+ },
639
+ update: {
640
+ sql: `update prisma_contract.marker set
641
+ core_hash = $2,
642
+ profile_hash = $3,
643
+ contract_json = $4::jsonb,
644
+ canonical_version = $5,
645
+ updated_at = now(),
646
+ app_tag = $6,
647
+ meta = $7::jsonb
648
+ where id = $1`,
649
+ params: baseParams
650
+ }
651
+ };
652
+ }
653
+
654
+ //#endregion
655
+ //#region src/codecs/json-schema-validation.ts
656
+ /**
657
+ * Validates a JSON value against its column's JSON Schema, if a validator exists.
658
+ *
659
+ * Throws `RUNTIME.JSON_SCHEMA_VALIDATION_FAILED` on validation failure.
660
+ * No-ops if no validator is registered for the column.
661
+ */
662
+ function validateJsonValue(registry, table, column, value, direction, codecId) {
663
+ const key = `${table}.${column}`;
664
+ const validate = registry.get(key);
665
+ if (!validate) return;
666
+ const result = validate(value);
667
+ if (result.valid) return;
668
+ throw createJsonSchemaValidationError(table, column, direction, result.errors, codecId);
669
+ }
670
+ function createJsonSchemaValidationError(table, column, direction, errors, codecId) {
671
+ return runtimeError("RUNTIME.JSON_SCHEMA_VALIDATION_FAILED", `JSON schema validation failed for column '${table}.${column}' (${direction}): ${formatErrorSummary(errors)}`, {
672
+ table,
673
+ column,
674
+ codecId,
675
+ direction,
676
+ errors: [...errors]
677
+ });
678
+ }
679
+ function formatErrorSummary(errors) {
680
+ if (errors.length === 0) return "unknown validation error";
681
+ if (errors.length === 1) {
682
+ const err = errors[0];
683
+ return err.path === "/" ? err.message : `${err.path}: ${err.message}`;
684
+ }
685
+ return errors.map((err) => err.path === "/" ? err.message : `${err.path}: ${err.message}`).join("; ");
686
+ }
687
+
688
+ //#endregion
689
+ //#region src/codecs/decoding.ts
690
+ function resolveRowCodec(alias, plan, registry) {
691
+ const planCodecId = plan.meta.annotations?.codecs?.[alias];
692
+ if (planCodecId) {
693
+ const codec$1 = registry.get(planCodecId);
694
+ if (codec$1) return codec$1;
695
+ }
696
+ if (plan.meta.projectionTypes) {
697
+ const typeId = plan.meta.projectionTypes[alias];
698
+ if (typeId) {
699
+ const codec$1 = registry.get(typeId);
700
+ if (codec$1) return codec$1;
701
+ }
702
+ }
703
+ return null;
704
+ }
705
+ /**
706
+ * Builds a lookup index from column name → { table, column } ref.
707
+ * Called once per decodeRow invocation to avoid O(aliases × refs) linear scans.
708
+ */
709
+ function buildColumnRefIndex(plan) {
710
+ const columns = plan.meta.refs?.columns;
711
+ if (!columns) return null;
712
+ const index = /* @__PURE__ */ new Map();
713
+ for (const ref of columns) index.set(ref.column, ref);
714
+ return index;
715
+ }
716
+ function parseProjectionRef(value) {
717
+ if (value.startsWith("include:") || value.startsWith("operation:")) return null;
718
+ const separatorIndex = value.indexOf(".");
719
+ if (separatorIndex <= 0 || separatorIndex === value.length - 1) return null;
720
+ return {
721
+ table: value.slice(0, separatorIndex),
722
+ column: value.slice(separatorIndex + 1)
723
+ };
724
+ }
725
+ function resolveColumnRefForAlias(alias, projection, fallbackColumnRefIndex) {
726
+ if (projection && !Array.isArray(projection)) {
727
+ const mappedRef = projection[alias];
728
+ if (typeof mappedRef !== "string") return;
729
+ return parseProjectionRef(mappedRef) ?? void 0;
730
+ }
731
+ return fallbackColumnRefIndex?.get(alias);
732
+ }
733
+ function decodeRow(row, plan, registry, jsonValidators) {
734
+ const decoded = {};
735
+ const projection = plan.meta.projection;
736
+ const fallbackColumnRefIndex = jsonValidators && (!projection || Array.isArray(projection)) ? buildColumnRefIndex(plan) : null;
737
+ let aliases;
738
+ if (projection && !Array.isArray(projection)) aliases = Object.keys(projection);
739
+ else if (projection && Array.isArray(projection)) aliases = projection;
740
+ else aliases = Object.keys(row);
741
+ for (const alias of aliases) {
742
+ const wireValue = row[alias];
743
+ const projectionValue = projection && typeof projection === "object" && !Array.isArray(projection) ? projection[alias] : void 0;
744
+ if (typeof projectionValue === "string" && projectionValue.startsWith("include:")) {
745
+ if (wireValue === null || wireValue === void 0) {
746
+ decoded[alias] = [];
747
+ continue;
748
+ }
749
+ try {
750
+ let parsed;
751
+ if (typeof wireValue === "string") parsed = JSON.parse(wireValue);
752
+ else if (Array.isArray(wireValue)) parsed = wireValue;
753
+ else parsed = JSON.parse(String(wireValue));
754
+ if (!Array.isArray(parsed)) throw new Error(`Expected array for include alias '${alias}', got ${typeof parsed}`);
755
+ decoded[alias] = parsed;
756
+ } catch (error) {
757
+ const decodeError = /* @__PURE__ */ new Error(`Failed to parse JSON array for include alias '${alias}': ${error instanceof Error ? error.message : String(error)}`);
758
+ decodeError.code = "RUNTIME.DECODE_FAILED";
759
+ decodeError.category = "RUNTIME";
760
+ decodeError.severity = "error";
761
+ decodeError.details = {
762
+ alias,
763
+ wirePreview: typeof wireValue === "string" && wireValue.length > 100 ? `${wireValue.substring(0, 100)}...` : String(wireValue).substring(0, 100)
764
+ };
765
+ throw decodeError;
766
+ }
767
+ continue;
768
+ }
769
+ if (wireValue === null || wireValue === void 0) {
770
+ decoded[alias] = wireValue;
771
+ continue;
772
+ }
773
+ const codec$1 = resolveRowCodec(alias, plan, registry);
774
+ if (!codec$1) {
775
+ decoded[alias] = wireValue;
776
+ continue;
777
+ }
778
+ try {
779
+ const decodedValue = codec$1.decode(wireValue);
780
+ if (jsonValidators) {
781
+ const ref = resolveColumnRefForAlias(alias, projection, fallbackColumnRefIndex);
782
+ if (ref) validateJsonValue(jsonValidators, ref.table, ref.column, decodedValue, "decode", codec$1.id);
783
+ }
784
+ decoded[alias] = decodedValue;
785
+ } catch (error) {
786
+ if (error instanceof Error && "code" in error && error.code === "RUNTIME.JSON_SCHEMA_VALIDATION_FAILED") throw error;
787
+ const decodeError = /* @__PURE__ */ new Error(`Failed to decode row alias '${alias}' with codec '${codec$1.id}': ${error instanceof Error ? error.message : String(error)}`);
788
+ decodeError.code = "RUNTIME.DECODE_FAILED";
789
+ decodeError.category = "RUNTIME";
790
+ decodeError.severity = "error";
791
+ decodeError.details = {
792
+ alias,
793
+ codec: codec$1.id,
794
+ wirePreview: typeof wireValue === "string" && wireValue.length > 100 ? `${wireValue.substring(0, 100)}...` : String(wireValue).substring(0, 100)
795
+ };
796
+ throw decodeError;
797
+ }
798
+ }
799
+ return decoded;
800
+ }
801
+
802
+ //#endregion
803
+ //#region src/codecs/encoding.ts
804
+ function resolveParamCodec(paramDescriptor, registry) {
805
+ if (paramDescriptor.codecId) {
806
+ const codec$1 = registry.get(paramDescriptor.codecId);
807
+ if (codec$1) return codec$1;
808
+ }
809
+ return null;
810
+ }
811
+ function encodeParam(value, paramDescriptor, paramIndex, registry) {
812
+ if (value === null || value === void 0) return null;
813
+ const codec$1 = resolveParamCodec(paramDescriptor, registry);
814
+ if (!codec$1) return value;
815
+ if (codec$1.encode) try {
816
+ return codec$1.encode(value);
817
+ } catch (error) {
818
+ const label = paramDescriptor.name ?? `param[${paramIndex}]`;
819
+ throw new Error(`Failed to encode parameter ${label}: ${error instanceof Error ? error.message : String(error)}`);
820
+ }
821
+ return value;
822
+ }
823
+ function encodeParams(plan, registry) {
824
+ if (plan.params.length === 0) return plan.params;
825
+ const encoded = [];
826
+ for (let i = 0; i < plan.params.length; i++) {
827
+ const paramValue = plan.params[i];
828
+ const paramDescriptor = plan.meta.paramDescriptors[i];
829
+ if (paramDescriptor) encoded.push(encodeParam(paramValue, paramDescriptor, i, registry));
830
+ else encoded.push(paramValue);
831
+ }
832
+ return Object.freeze(encoded);
833
+ }
834
+
835
+ //#endregion
836
+ //#region src/sql-family-adapter.ts
837
+ var SqlFamilyAdapter = class {
838
+ contract;
839
+ markerReader;
840
+ constructor(contract, adapterProfile) {
841
+ this.contract = contract;
842
+ this.markerReader = adapterProfile;
843
+ }
844
+ validatePlan(plan, contract) {
845
+ if (plan.meta.target !== contract.target) throw runtimeError("PLAN.TARGET_MISMATCH", "Plan target does not match runtime target", {
846
+ planTarget: plan.meta.target,
847
+ runtimeTarget: contract.target
848
+ });
849
+ if (plan.meta.storageHash !== contract.storage.storageHash) throw runtimeError("PLAN.HASH_MISMATCH", "Plan storage hash does not match runtime contract", {
850
+ planStorageHash: plan.meta.storageHash,
851
+ runtimeStorageHash: contract.storage.storageHash
852
+ });
853
+ }
854
+ };
855
+
856
+ //#endregion
857
+ //#region src/sql-runtime.ts
858
+ var SqlRuntimeImpl = class {
859
+ core;
860
+ contract;
861
+ adapter;
862
+ codecRegistry;
863
+ jsonSchemaValidators;
864
+ codecRegistryValidated;
865
+ constructor(options) {
866
+ const { context, adapter, driver, verify, plugins, mode, log } = options;
867
+ this.contract = context.contract;
868
+ this.adapter = adapter;
869
+ this.codecRegistry = context.codecs;
870
+ this.jsonSchemaValidators = context.jsonSchemaValidators;
871
+ this.codecRegistryValidated = false;
872
+ this.core = createRuntimeCore({
873
+ familyAdapter: new SqlFamilyAdapter(context.contract, adapter.profile),
874
+ driver,
875
+ verify,
876
+ plugins,
877
+ ...ifDefined("mode", mode),
878
+ ...ifDefined("log", log)
879
+ });
880
+ if (verify.mode === "startup") {
881
+ validateCodecRegistryCompleteness(this.codecRegistry, context.contract);
882
+ this.codecRegistryValidated = true;
883
+ }
884
+ }
885
+ ensureCodecRegistryValidated(contract) {
886
+ if (!this.codecRegistryValidated) {
887
+ validateCodecRegistryCompleteness(this.codecRegistry, contract);
888
+ this.codecRegistryValidated = true;
889
+ }
890
+ }
891
+ toExecutionPlan(plan) {
892
+ const isSqlQueryPlan = (p) => {
893
+ return "ast" in p && !("sql" in p);
894
+ };
895
+ return isSqlQueryPlan(plan) ? lowerSqlPlan(this.adapter, this.contract, plan) : plan;
896
+ }
897
+ executeAgainstQueryable(plan, queryable) {
898
+ this.ensureCodecRegistryValidated(this.contract);
899
+ const executablePlan = this.toExecutionPlan(plan);
900
+ const iterator = async function* (self) {
901
+ const encodedParams = encodeParams(executablePlan, self.codecRegistry);
902
+ const planWithEncodedParams = {
903
+ ...executablePlan,
904
+ params: encodedParams
905
+ };
906
+ const coreIterator = queryable.execute(planWithEncodedParams);
907
+ for await (const rawRow of coreIterator) yield decodeRow(rawRow, executablePlan, self.codecRegistry, self.jsonSchemaValidators);
908
+ };
909
+ return new AsyncIterableResult(iterator(this));
910
+ }
911
+ execute(plan) {
912
+ return this.executeAgainstQueryable(plan, this.core);
913
+ }
914
+ async connection() {
915
+ const coreConn = await this.core.connection();
916
+ const self = this;
917
+ return {
918
+ async transaction() {
919
+ const coreTx = await coreConn.transaction();
920
+ return {
921
+ commit: coreTx.commit.bind(coreTx),
922
+ rollback: coreTx.rollback.bind(coreTx),
923
+ execute(plan) {
924
+ return self.executeAgainstQueryable(plan, coreTx);
925
+ }
926
+ };
927
+ },
928
+ release: coreConn.release.bind(coreConn),
929
+ execute(plan) {
930
+ return self.executeAgainstQueryable(plan, coreConn);
931
+ }
932
+ };
933
+ }
934
+ telemetry() {
935
+ return this.core.telemetry();
936
+ }
937
+ close() {
938
+ return this.core.close();
939
+ }
940
+ };
941
+ function createRuntime(options) {
942
+ const { stackInstance, context, driver, verify, plugins, mode, log } = options;
943
+ return new SqlRuntimeImpl({
944
+ context,
945
+ adapter: stackInstance.adapter,
946
+ driver,
947
+ verify,
948
+ ...ifDefined("plugins", plugins),
949
+ ...ifDefined("mode", mode),
950
+ ...ifDefined("log", log)
951
+ });
952
+ }
953
+
954
+ //#endregion
955
+ export { writeContractMarker as a, lints as c, extractCodecIds as d, validateCodecRegistryCompleteness as f, readContractMarker as i, budgets as l, ensureSchemaStatement as n, createExecutionContext as o, validateContractCodecMappings as p, ensureTableStatement as r, createSqlExecutionStack as s, createRuntime as t, lowerSqlPlan as u };
956
+ //# sourceMappingURL=exports-DGa0ipuP.mjs.map