@prisma-next/sql-runtime 0.3.0-dev.7 → 0.3.0-dev.71

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 (166) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +137 -26
  3. package/dist/exports-BhZqJPVb.mjs +771 -0
  4. package/dist/exports-BhZqJPVb.mjs.map +1 -0
  5. package/dist/index-D59jqEKF.d.mts +159 -0
  6. package/dist/index-D59jqEKF.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 +82 -0
  10. package/dist/test/utils.d.mts.map +1 -0
  11. package/dist/test/utils.mjs +212 -0
  12. package/dist/test/utils.mjs.map +1 -0
  13. package/package.json +32 -25
  14. package/src/codecs/decoding.ts +84 -3
  15. package/src/codecs/encoding.ts +15 -2
  16. package/src/codecs/json-schema-validation.ts +61 -0
  17. package/src/exports/index.ts +14 -6
  18. package/src/lower-sql-plan.ts +8 -8
  19. package/src/plugins/lints.ts +204 -0
  20. package/src/sql-context.ts +385 -98
  21. package/src/sql-family-adapter.ts +9 -5
  22. package/src/sql-marker.ts +2 -2
  23. package/src/sql-runtime.ts +131 -31
  24. package/test/async-iterable-result.test.ts +42 -34
  25. package/test/context.types.test-d.ts +68 -0
  26. package/test/execution-stack.test.ts +166 -0
  27. package/test/json-schema-validation.test.ts +653 -0
  28. package/test/lints.test.ts +330 -0
  29. package/test/parameterized-types.test.ts +539 -0
  30. package/test/sql-context.test.ts +292 -117
  31. package/test/sql-family-adapter.test.ts +7 -6
  32. package/test/sql-runtime.test.ts +218 -30
  33. package/test/utils.ts +80 -51
  34. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
  35. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
  36. package/dist/amcheck-24VY6X5V.js +0 -13
  37. package/dist/amcheck-24VY6X5V.js.map +0 -1
  38. package/dist/bloom-VS74NLHT.js +0 -13
  39. package/dist/bloom-VS74NLHT.js.map +0 -1
  40. package/dist/btree_gin-WBC4EAAI.js +0 -13
  41. package/dist/btree_gin-WBC4EAAI.js.map +0 -1
  42. package/dist/btree_gist-UNC6QD3M.js +0 -13
  43. package/dist/btree_gist-UNC6QD3M.js.map +0 -1
  44. package/dist/chunk-3KTOEDFX.js +0 -49
  45. package/dist/chunk-3KTOEDFX.js.map +0 -1
  46. package/dist/chunk-47DZBRQC.js +0 -1280
  47. package/dist/chunk-47DZBRQC.js.map +0 -1
  48. package/dist/chunk-52N6AFZM.js +0 -133
  49. package/dist/chunk-52N6AFZM.js.map +0 -1
  50. package/dist/chunk-7D4SUZUM.js +0 -38
  51. package/dist/chunk-7D4SUZUM.js.map +0 -1
  52. package/dist/chunk-C6I3V3DM.js +0 -455
  53. package/dist/chunk-C6I3V3DM.js.map +0 -1
  54. package/dist/chunk-ECWIHLAT.js +0 -37
  55. package/dist/chunk-ECWIHLAT.js.map +0 -1
  56. package/dist/chunk-EI626SDC.js +0 -105
  57. package/dist/chunk-EI626SDC.js.map +0 -1
  58. package/dist/chunk-UKKOYUGL.js +0 -578
  59. package/dist/chunk-UKKOYUGL.js.map +0 -1
  60. package/dist/chunk-XPLNMXQV.js +0 -1537
  61. package/dist/chunk-XPLNMXQV.js.map +0 -1
  62. package/dist/citext-T7MXGUY7.js +0 -13
  63. package/dist/citext-T7MXGUY7.js.map +0 -1
  64. package/dist/client-5FENX6AW.js +0 -299
  65. package/dist/client-5FENX6AW.js.map +0 -1
  66. package/dist/cube-TFDQBZCI.js +0 -13
  67. package/dist/cube-TFDQBZCI.js.map +0 -1
  68. package/dist/dict_int-AEUOPGWP.js +0 -13
  69. package/dist/dict_int-AEUOPGWP.js.map +0 -1
  70. package/dist/dict_xsyn-DAAYX3FL.js +0 -13
  71. package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
  72. package/dist/dist-AQ3LWXOX.js +0 -570
  73. package/dist/dist-AQ3LWXOX.js.map +0 -1
  74. package/dist/dist-LBVX6BJW.js +0 -189
  75. package/dist/dist-LBVX6BJW.js.map +0 -1
  76. package/dist/dist-WLKUVDN2.js +0 -5127
  77. package/dist/dist-WLKUVDN2.js.map +0 -1
  78. package/dist/earthdistance-KIGTF4LE.js +0 -13
  79. package/dist/earthdistance-KIGTF4LE.js.map +0 -1
  80. package/dist/file_fdw-5N55UP6I.js +0 -13
  81. package/dist/file_fdw-5N55UP6I.js.map +0 -1
  82. package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
  83. package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
  84. package/dist/hstore-YX726NKN.js +0 -13
  85. package/dist/hstore-YX726NKN.js.map +0 -1
  86. package/dist/http-exception-FZY2H4OF.js +0 -8
  87. package/dist/http-exception-FZY2H4OF.js.map +0 -1
  88. package/dist/index.js +0 -30
  89. package/dist/index.js.map +0 -1
  90. package/dist/intarray-NKVXNO2D.js +0 -13
  91. package/dist/intarray-NKVXNO2D.js.map +0 -1
  92. package/dist/isn-FTEMJGEV.js +0 -13
  93. package/dist/isn-FTEMJGEV.js.map +0 -1
  94. package/dist/lo-DB7L4NGI.js +0 -13
  95. package/dist/lo-DB7L4NGI.js.map +0 -1
  96. package/dist/logger-WQ7SHNDD.js +0 -68
  97. package/dist/logger-WQ7SHNDD.js.map +0 -1
  98. package/dist/ltree-Z32TZT6W.js +0 -13
  99. package/dist/ltree-Z32TZT6W.js.map +0 -1
  100. package/dist/nodefs-NM46ACH7.js +0 -31
  101. package/dist/nodefs-NM46ACH7.js.map +0 -1
  102. package/dist/opfs-ahp-NJO33LVZ.js +0 -332
  103. package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
  104. package/dist/pageinspect-YP3IZR4X.js +0 -13
  105. package/dist/pageinspect-YP3IZR4X.js.map +0 -1
  106. package/dist/pg_buffercache-7TD5J2FB.js +0 -13
  107. package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
  108. package/dist/pg_dump-SG4KYBUB.js +0 -2492
  109. package/dist/pg_dump-SG4KYBUB.js.map +0 -1
  110. package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
  111. package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
  112. package/dist/pg_surgery-J2MUEWEP.js +0 -13
  113. package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
  114. package/dist/pg_trgm-7VNQOYS6.js +0 -13
  115. package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
  116. package/dist/pg_visibility-TTSIPHFL.js +0 -13
  117. package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
  118. package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
  119. package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
  120. package/dist/proxy-signals-GUDAMDHV.js +0 -39
  121. package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
  122. package/dist/seg-IYVDLE4O.js +0 -13
  123. package/dist/seg-IYVDLE4O.js.map +0 -1
  124. package/dist/src/codecs/decoding.d.ts +0 -4
  125. package/dist/src/codecs/decoding.d.ts.map +0 -1
  126. package/dist/src/codecs/encoding.d.ts +0 -5
  127. package/dist/src/codecs/encoding.d.ts.map +0 -1
  128. package/dist/src/codecs/validation.d.ts +0 -6
  129. package/dist/src/codecs/validation.d.ts.map +0 -1
  130. package/dist/src/exports/index.d.ts +0 -11
  131. package/dist/src/exports/index.d.ts.map +0 -1
  132. package/dist/src/index.d.ts +0 -2
  133. package/dist/src/index.d.ts.map +0 -1
  134. package/dist/src/lower-sql-plan.d.ts +0 -15
  135. package/dist/src/lower-sql-plan.d.ts.map +0 -1
  136. package/dist/src/sql-context.d.ts +0 -65
  137. package/dist/src/sql-context.d.ts.map +0 -1
  138. package/dist/src/sql-family-adapter.d.ts +0 -10
  139. package/dist/src/sql-family-adapter.d.ts.map +0 -1
  140. package/dist/src/sql-marker.d.ts +0 -22
  141. package/dist/src/sql-marker.d.ts.map +0 -1
  142. package/dist/src/sql-runtime.d.ts +0 -25
  143. package/dist/src/sql-runtime.d.ts.map +0 -1
  144. package/dist/tablefunc-EF4RCS7S.js +0 -13
  145. package/dist/tablefunc-EF4RCS7S.js.map +0 -1
  146. package/dist/tcn-3VT5BQYW.js +0 -13
  147. package/dist/tcn-3VT5BQYW.js.map +0 -1
  148. package/dist/test/utils.d.ts +0 -59
  149. package/dist/test/utils.d.ts.map +0 -1
  150. package/dist/test/utils.js +0 -24634
  151. package/dist/test/utils.js.map +0 -1
  152. package/dist/tiny-CW6F4GX6.js +0 -10
  153. package/dist/tiny-CW6F4GX6.js.map +0 -1
  154. package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
  155. package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
  156. package/dist/tsm_system_time-76WEIMBG.js +0 -13
  157. package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
  158. package/dist/unaccent-7RYF3R64.js +0 -13
  159. package/dist/unaccent-7RYF3R64.js.map +0 -1
  160. package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
  161. package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
  162. package/dist/uuid_ossp-4ETE4FPE.js +0 -13
  163. package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
  164. package/dist/vector-74GPNV7V.js +0 -13
  165. package/dist/vector-74GPNV7V.js.map +0 -1
  166. package/src/index.ts +0 -1
@@ -1,4 +1,6 @@
1
1
  import type { ExecutionPlan } from '@prisma-next/contract/types';
2
+ import type { ExecutionStackInstance } from '@prisma-next/core-execution-plane/stack';
3
+ import type { RuntimeDriverInstance } from '@prisma-next/core-execution-plane/types';
2
4
  import type { OperationRegistry } from '@prisma-next/operations';
3
5
  import type {
4
6
  Log,
@@ -15,41 +17,90 @@ import type {
15
17
  Adapter,
16
18
  CodecRegistry,
17
19
  LoweredStatement,
20
+ QueryAst,
18
21
  SelectAst,
19
22
  SqlDriver,
20
23
  } from '@prisma-next/sql-relational-core/ast';
21
24
  import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
25
+ import type { JsonSchemaValidatorRegistry } from '@prisma-next/sql-relational-core/query-lane-context';
26
+ import { ifDefined } from '@prisma-next/utils/defined';
22
27
  import { decodeRow } from './codecs/decoding';
23
28
  import { encodeParams } from './codecs/encoding';
24
29
  import { validateCodecRegistryCompleteness } from './codecs/validation';
25
30
  import { lowerSqlPlan } from './lower-sql-plan';
26
- import type { RuntimeContext } from './sql-context';
31
+ import type {
32
+ ExecutionContext,
33
+ SqlRuntimeAdapterInstance,
34
+ SqlRuntimeExtensionInstance,
35
+ } from './sql-context';
27
36
  import { SqlFamilyAdapter } from './sql-family-adapter';
28
37
 
29
38
  export interface RuntimeOptions<
30
39
  TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
31
40
  > {
32
- readonly driver: SqlDriver;
41
+ readonly context: ExecutionContext<TContract>;
42
+ readonly adapter: Adapter<QueryAst, SqlContract<SqlStorage>, LoweredStatement>;
43
+ readonly driver: SqlDriver<unknown>;
33
44
  readonly verify: RuntimeVerifyOptions;
34
- readonly context: RuntimeContext<TContract>;
35
45
  readonly plugins?: readonly Plugin<
36
46
  TContract,
37
47
  Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
38
- SqlDriver
48
+ SqlDriver<unknown>
39
49
  >[];
40
50
  readonly mode?: 'strict' | 'permissive';
41
51
  readonly log?: Log;
42
52
  }
43
53
 
44
- export interface Runtime {
45
- execute<Row = Record<string, unknown>>(
46
- plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
47
- ): AsyncIterableResult<Row>;
54
+ export interface CreateRuntimeOptions<
55
+ TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
56
+ TTargetId extends string = string,
57
+ > {
58
+ readonly stackInstance: ExecutionStackInstance<
59
+ 'sql',
60
+ TTargetId,
61
+ SqlRuntimeAdapterInstance<TTargetId>,
62
+ RuntimeDriverInstance<'sql', TTargetId>,
63
+ SqlRuntimeExtensionInstance<TTargetId>
64
+ >;
65
+ readonly context: ExecutionContext<TContract>;
66
+ readonly driver: SqlDriver<unknown>;
67
+ readonly verify: RuntimeVerifyOptions;
68
+ readonly plugins?: readonly Plugin<
69
+ TContract,
70
+ Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
71
+ SqlDriver<unknown>
72
+ >[];
73
+ readonly mode?: 'strict' | 'permissive';
74
+ readonly log?: Log;
75
+ }
76
+
77
+ export interface Runtime extends RuntimeQueryable {
78
+ connection(): Promise<RuntimeConnection>;
48
79
  telemetry(): RuntimeTelemetryEvent | null;
49
80
  close(): Promise<void>;
50
81
  operations(): OperationRegistry;
51
82
  }
52
83
 
84
+ export interface RuntimeConnection extends RuntimeQueryable {
85
+ transaction(): Promise<RuntimeTransaction>;
86
+ release(): Promise<void>;
87
+ }
88
+
89
+ export interface RuntimeTransaction extends RuntimeQueryable {
90
+ commit(): Promise<void>;
91
+ rollback(): Promise<void>;
92
+ }
93
+
94
+ export interface RuntimeQueryable {
95
+ execute<Row = Record<string, unknown>>(
96
+ plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
97
+ ): AsyncIterableResult<Row>;
98
+ }
99
+
100
+ interface CoreQueryable {
101
+ execute<Row = Record<string, unknown>>(plan: ExecutionPlan<Row>): AsyncIterableResult<Row>;
102
+ }
103
+
53
104
  export type { RuntimeTelemetryEvent, RuntimeVerifyOptions, TelemetryOutcome };
54
105
 
55
106
  class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>>
@@ -58,18 +109,20 @@ class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<Sql
58
109
  private readonly core: RuntimeCore<
59
110
  TContract,
60
111
  Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
61
- SqlDriver
112
+ SqlDriver<unknown>
62
113
  >;
63
114
  private readonly contract: TContract;
64
- private readonly context: RuntimeContext<TContract>;
115
+ private readonly adapter: Adapter<QueryAst, SqlContract<SqlStorage>, LoweredStatement>;
65
116
  private readonly codecRegistry: CodecRegistry;
117
+ private readonly jsonSchemaValidators: JsonSchemaValidatorRegistry | undefined;
66
118
  private codecRegistryValidated: boolean;
67
119
 
68
120
  constructor(options: RuntimeOptions<TContract>) {
69
- const { context, driver, verify, plugins, mode, log } = options;
121
+ const { context, adapter, driver, verify, plugins, mode, log } = options;
70
122
  this.contract = context.contract;
71
- this.context = context;
123
+ this.adapter = adapter;
72
124
  this.codecRegistry = context.codecs;
125
+ this.jsonSchemaValidators = context.jsonSchemaValidators;
73
126
  this.codecRegistryValidated = false;
74
127
 
75
128
  const familyAdapter = new SqlFamilyAdapter(context.contract);
@@ -77,7 +130,7 @@ class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<Sql
77
130
  const coreOptions: RuntimeCoreOptions<
78
131
  TContract,
79
132
  Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
80
- SqlDriver
133
+ SqlDriver<unknown>
81
134
  > = {
82
135
  familyAdapter,
83
136
  driver,
@@ -85,10 +138,10 @@ class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<Sql
85
138
  plugins: plugins as readonly Plugin<
86
139
  TContract,
87
140
  Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
88
- SqlDriver
141
+ SqlDriver<unknown>
89
142
  >[],
90
- ...(mode !== undefined ? { mode } : {}),
91
- ...(log !== undefined ? { log } : {}),
143
+ ...ifDefined('mode', mode),
144
+ ...ifDefined('log', log),
92
145
  operationRegistry: context.operations,
93
146
  };
94
147
 
@@ -107,37 +160,42 @@ class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<Sql
107
160
  }
108
161
  }
109
162
 
110
- execute<Row = Record<string, unknown>>(
111
- plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
112
- ): AsyncIterableResult<Row> {
113
- this.ensureCodecRegistryValidated(this.contract);
114
-
115
- // Check if plan is SqlQueryPlan (has ast but no sql)
163
+ private toExecutionPlan<Row>(plan: ExecutionPlan<Row> | SqlQueryPlan<Row>): ExecutionPlan<Row> {
116
164
  const isSqlQueryPlan = (p: ExecutionPlan<Row> | SqlQueryPlan<Row>): p is SqlQueryPlan<Row> => {
117
165
  return 'ast' in p && !('sql' in p);
118
166
  };
119
167
 
120
- // Lower SqlQueryPlan to Plan if needed
121
- const executablePlan: ExecutionPlan<Row> = isSqlQueryPlan(plan)
122
- ? lowerSqlPlan(this.context, plan)
123
- : plan;
168
+ return isSqlQueryPlan(plan) ? lowerSqlPlan(this.adapter, this.contract, plan) : plan;
169
+ }
170
+
171
+ private executeAgainstQueryable<Row = Record<string, unknown>>(
172
+ plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
173
+ queryable: CoreQueryable,
174
+ ): AsyncIterableResult<Row> {
175
+ this.ensureCodecRegistryValidated(this.contract);
176
+ const executablePlan = this.toExecutionPlan(plan);
124
177
 
125
178
  const iterator = async function* (
126
179
  self: SqlRuntimeImpl<TContract>,
127
180
  ): AsyncGenerator<Row, void, unknown> {
128
- const encodedParams = encodeParams(executablePlan, self.codecRegistry);
181
+ const encodedParams = encodeParams(
182
+ executablePlan,
183
+ self.codecRegistry,
184
+ self.jsonSchemaValidators,
185
+ );
129
186
  const planWithEncodedParams: ExecutionPlan<Row> = {
130
187
  ...executablePlan,
131
188
  params: encodedParams,
132
189
  };
133
190
 
134
- const coreIterator = self.core.execute(planWithEncodedParams);
191
+ const coreIterator = queryable.execute(planWithEncodedParams);
135
192
 
136
193
  for await (const rawRow of coreIterator) {
137
194
  const decodedRow = decodeRow(
138
195
  rawRow as Record<string, unknown>,
139
196
  executablePlan,
140
197
  self.codecRegistry,
198
+ self.jsonSchemaValidators,
141
199
  );
142
200
  yield decodedRow as Row;
143
201
  }
@@ -146,6 +204,38 @@ class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<Sql
146
204
  return new AsyncIterableResult(iterator(this));
147
205
  }
148
206
 
207
+ execute<Row = Record<string, unknown>>(
208
+ plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
209
+ ): AsyncIterableResult<Row> {
210
+ return this.executeAgainstQueryable(plan, this.core);
211
+ }
212
+
213
+ async connection(): Promise<RuntimeConnection> {
214
+ const coreConn = await this.core.connection();
215
+ const self = this;
216
+ const wrappedConnection: RuntimeConnection = {
217
+ async transaction(): Promise<RuntimeTransaction> {
218
+ const coreTx = await coreConn.transaction();
219
+ return {
220
+ commit: coreTx.commit.bind(coreTx),
221
+ rollback: coreTx.rollback.bind(coreTx),
222
+ execute<Row = Record<string, unknown>>(
223
+ plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
224
+ ): AsyncIterableResult<Row> {
225
+ return self.executeAgainstQueryable(plan, coreTx);
226
+ },
227
+ };
228
+ },
229
+ release: coreConn.release.bind(coreConn),
230
+ execute<Row = Record<string, unknown>>(
231
+ plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
232
+ ): AsyncIterableResult<Row> {
233
+ return self.executeAgainstQueryable(plan, coreConn);
234
+ },
235
+ };
236
+ return wrappedConnection;
237
+ }
238
+
149
239
  telemetry(): RuntimeTelemetryEvent | null {
150
240
  return this.core.telemetry();
151
241
  }
@@ -159,8 +249,18 @@ class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<Sql
159
249
  }
160
250
  }
161
251
 
162
- export function createRuntime<TContract extends SqlContract<SqlStorage>>(
163
- options: RuntimeOptions<TContract>,
252
+ export function createRuntime<TContract extends SqlContract<SqlStorage>, TTargetId extends string>(
253
+ options: CreateRuntimeOptions<TContract, TTargetId>,
164
254
  ): Runtime {
165
- return new SqlRuntimeImpl(options);
255
+ const { stackInstance, context, driver, verify, plugins, mode, log } = options;
256
+
257
+ return new SqlRuntimeImpl({
258
+ context,
259
+ adapter: stackInstance.adapter,
260
+ driver,
261
+ verify,
262
+ ...ifDefined('plugins', plugins),
263
+ ...ifDefined('mode', mode),
264
+ ...ifDefined('log', log),
265
+ });
166
266
  }
@@ -1,10 +1,17 @@
1
1
  import type { ExecutionPlan } from '@prisma-next/contract/types';
2
+ import { instantiateExecutionStack } from '@prisma-next/core-execution-plane/stack';
2
3
  import type { AsyncIterableResult } from '@prisma-next/runtime-executor';
3
4
  import { describe, expect, it } from 'vitest';
4
- import { createRuntime } from '../src/exports';
5
- import { createStubAdapter, createTestContext, createTestContract } from './utils';
5
+ import type { Runtime } from '../src/exports';
6
+ import { createRuntime, createSqlExecutionStack } from '../src/exports';
7
+ import {
8
+ createStubAdapter,
9
+ createTestAdapterDescriptor,
10
+ createTestContext,
11
+ createTestContract,
12
+ createTestTargetDescriptor,
13
+ } from './utils';
6
14
 
7
- // Mock driver that implements SqlDriver interface
8
15
  class MockDriver {
9
16
  private rows: ReadonlyArray<Record<string, unknown>> = [];
10
17
 
@@ -12,11 +19,10 @@ class MockDriver {
12
19
  this.rows = rows;
13
20
  }
14
21
 
15
- async query(
22
+ async query<Row = Record<string, unknown>>(
16
23
  _sql: string,
17
- _params: readonly unknown[],
18
- ): Promise<{ rows: ReadonlyArray<unknown> }> {
19
- // Return empty marker result for contract verification
24
+ _params?: readonly unknown[],
25
+ ): Promise<{ rows: ReadonlyArray<Row> }> {
20
26
  return { rows: [] };
21
27
  }
22
28
 
@@ -29,20 +35,20 @@ class MockDriver {
29
35
  }
30
36
  }
31
37
 
32
- async connect(): Promise<void> {
33
- // No-op
38
+ async acquireConnection(): Promise<never> {
39
+ throw new Error('Not implemented in mock');
34
40
  }
35
41
 
36
- async close(): Promise<void> {
37
- // No-op
38
- }
42
+ async connect(): Promise<void> {}
43
+
44
+ async close(): Promise<void> {}
39
45
  }
40
46
 
41
47
  const fixtureContract = createTestContract({
42
48
  schemaVersion: '1',
43
49
  targetFamily: 'sql',
44
50
  target: 'postgres',
45
- coreHash: 'test-hash',
51
+ storageHash: 'test-hash',
46
52
  profileHash: 'test-profile-hash',
47
53
  storage: {
48
54
  tables: {
@@ -62,20 +68,31 @@ const fixtureContract = createTestContract({
62
68
  mappings: { codecTypes: {}, operationTypes: {} },
63
69
  });
64
70
 
71
+ function createTestRuntime(mockDriver: MockDriver): Runtime {
72
+ const adapter = createStubAdapter();
73
+ const stack = createSqlExecutionStack({
74
+ target: createTestTargetDescriptor(),
75
+ adapter: createTestAdapterDescriptor(adapter),
76
+ extensionPacks: [],
77
+ });
78
+ const stackInstance = instantiateExecutionStack(stack);
79
+ const context = createTestContext(fixtureContract, adapter);
80
+ return createRuntime({
81
+ stackInstance,
82
+ context,
83
+ driver: mockDriver,
84
+ verify: { mode: 'onFirstUse', requireMarker: false },
85
+ });
86
+ }
87
+
65
88
  describe('SqlRuntime AsyncIterableResult integration', () => {
66
89
  it('returns AsyncIterableResult from execute', async () => {
67
- const adapter = createStubAdapter();
68
90
  const driver = new MockDriver();
69
91
  driver.setRows([
70
92
  { id: 1, email: 'test1@example.com' },
71
93
  { id: 2, email: 'test2@example.com' },
72
94
  ]);
73
- const context = createTestContext(fixtureContract, adapter);
74
- const runtime = createRuntime({
75
- driver: driver as unknown as Parameters<typeof createRuntime>[0]['driver'],
76
- context,
77
- verify: { mode: 'onFirstUse', requireMarker: false },
78
- });
95
+ const runtime = createTestRuntime(driver);
79
96
 
80
97
  const plan: ExecutionPlan<{ id: number; email: string }> = {
81
98
  sql: 'SELECT id, email FROM "user" ORDER BY id',
@@ -83,7 +100,7 @@ describe('SqlRuntime AsyncIterableResult integration', () => {
83
100
  meta: {
84
101
  target: 'postgres',
85
102
  targetFamily: 'sql',
86
- coreHash: 'test-hash',
103
+ storageHash: 'test-hash',
87
104
  lane: 'sql',
88
105
  paramDescriptors: [],
89
106
  },
@@ -91,7 +108,6 @@ describe('SqlRuntime AsyncIterableResult integration', () => {
91
108
 
92
109
  const result = runtime.execute(plan);
93
110
 
94
- // Verify it's an AsyncIterableResult
95
111
  expect(result).toBeInstanceOf(Object);
96
112
  expect(typeof result.toArray).toBe('function');
97
113
  expect(typeof result[Symbol.asyncIterator]).toBe('function');
@@ -100,15 +116,9 @@ describe('SqlRuntime AsyncIterableResult integration', () => {
100
116
  });
101
117
 
102
118
  it('preserves type information', async () => {
103
- const adapter = createStubAdapter();
104
119
  const driver = new MockDriver();
105
120
  driver.setRows([{ id: 1, email: 'test@example.com' }]);
106
- const context = createTestContext(fixtureContract, adapter);
107
- const runtime = createRuntime({
108
- driver: driver as unknown as Parameters<typeof createRuntime>[0]['driver'],
109
- context,
110
- verify: { mode: 'onFirstUse', requireMarker: false },
111
- });
121
+ const runtime = createTestRuntime(driver);
112
122
 
113
123
  const plan: ExecutionPlan<{ id: number; email: string }> = {
114
124
  sql: 'SELECT id, email FROM "user" LIMIT 1',
@@ -116,7 +126,7 @@ describe('SqlRuntime AsyncIterableResult integration', () => {
116
126
  meta: {
117
127
  target: 'postgres',
118
128
  targetFamily: 'sql',
119
- coreHash: 'test-hash',
129
+ storageHash: 'test-hash',
120
130
  lane: 'sql',
121
131
  paramDescriptors: [],
122
132
  },
@@ -126,10 +136,8 @@ describe('SqlRuntime AsyncIterableResult integration', () => {
126
136
  const rows = await result.toArray();
127
137
 
128
138
  expect(rows.length).toBe(1);
129
- if (rows[0]) {
130
- expect(typeof rows[0].id).toBe('number');
131
- expect(typeof rows[0].email).toBe('string');
132
- }
139
+ expect(typeof rows[0]!.id).toBe('number');
140
+ expect(typeof rows[0]!.email).toBe('string');
133
141
 
134
142
  await runtime.close();
135
143
  });
@@ -0,0 +1,68 @@
1
+ import type { SqlContract, SqlMappings, SqlStorage } from '@prisma-next/sql-contract/types';
2
+ import { expectTypeOf, test } from 'vitest';
3
+ import type { ExecutionContext, TypeHelperRegistry } from '../src/sql-context';
4
+
5
+ // Contract type with storage.types using literal types (matching emission output)
6
+ type TestContract = SqlContract<
7
+ {
8
+ readonly tables: {
9
+ readonly document: {
10
+ readonly columns: {
11
+ readonly id: {
12
+ readonly nativeType: 'int4';
13
+ readonly codecId: 'pg/int4@1';
14
+ nullable: false;
15
+ };
16
+ };
17
+ readonly primaryKey: { readonly columns: readonly ['id'] };
18
+ readonly uniques: readonly [];
19
+ readonly indexes: readonly [];
20
+ readonly foreignKeys: readonly [];
21
+ };
22
+ };
23
+ readonly types: {
24
+ readonly Vector1536: {
25
+ readonly codecId: 'pg/vector@1';
26
+ readonly nativeType: 'vector';
27
+ readonly typeParams: { readonly length: 1536 };
28
+ };
29
+ };
30
+ },
31
+ Record<string, never>,
32
+ Record<string, never>,
33
+ SqlMappings
34
+ >;
35
+
36
+ test('ExecutionContext.types is TypeHelperRegistry', () => {
37
+ // ExecutionContext.types is intentionally loose (Record<string, unknown>)
38
+ // The strong typing comes from schema(context).types via ExtractSchemaTypes
39
+ expectTypeOf<ExecutionContext<TestContract>['types']>().toEqualTypeOf<TypeHelperRegistry>();
40
+
41
+ // TypeHelperRegistry allows any values - the actual type depends on init hooks
42
+ expectTypeOf<TypeHelperRegistry>().toEqualTypeOf<Record<string, unknown>>();
43
+ });
44
+
45
+ test('ExecutionContext preserves contract type parameter', () => {
46
+ // Verify the contract type is preserved in ExecutionContext
47
+ expectTypeOf<ExecutionContext<TestContract>['contract']>().toEqualTypeOf<TestContract>();
48
+
49
+ // Verify we can access storage.types through the context's contract
50
+ type ContractStorageTypes = ExecutionContext<TestContract>['contract']['storage']['types'];
51
+ expectTypeOf<ContractStorageTypes>().toExtend<
52
+ | {
53
+ readonly Vector1536: {
54
+ readonly codecId: 'pg/vector@1';
55
+ readonly nativeType: 'vector';
56
+ readonly typeParams: { readonly length: 1536 };
57
+ };
58
+ }
59
+ | undefined
60
+ >();
61
+ });
62
+
63
+ test('ExecutionContext accepts generic SqlContract', () => {
64
+ // Verify ExecutionContext defaults work
65
+ type DefaultContext = ExecutionContext;
66
+ expectTypeOf<DefaultContext['contract']>().toExtend<SqlContract<SqlStorage>>();
67
+ expectTypeOf<DefaultContext['types']>().toEqualTypeOf<TypeHelperRegistry>();
68
+ });
@@ -0,0 +1,166 @@
1
+ import { createExecutionStack } from '@prisma-next/core-execution-plane/stack';
2
+ import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { createExecutionContext, createSqlExecutionStack } from '../src/exports';
5
+ import type {
6
+ ExecutionContext,
7
+ SqlRuntimeAdapterDescriptor,
8
+ SqlRuntimeExtensionDescriptor,
9
+ SqlRuntimeTargetDescriptor,
10
+ } from '../src/sql-context';
11
+ import { createTestContract } from './utils';
12
+
13
+ function createStubAdapterDescriptor(): SqlRuntimeAdapterDescriptor<'postgres'> {
14
+ const registry = createCodecRegistry();
15
+ registry.register(
16
+ codec({
17
+ typeId: 'pg/text@1',
18
+ targetTypes: ['text'],
19
+ encode: (value: string) => value,
20
+ decode: (wire: string) => wire,
21
+ }),
22
+ );
23
+
24
+ return {
25
+ kind: 'adapter',
26
+ id: 'test-adapter',
27
+ version: '0.0.1',
28
+ familyId: 'sql' as const,
29
+ targetId: 'postgres' as const,
30
+ codecs: () => registry,
31
+ operationSignatures: () => [],
32
+ parameterizedCodecs: () => [],
33
+ create() {
34
+ return Object.assign(
35
+ { familyId: 'sql' as const, targetId: 'postgres' as const },
36
+ {
37
+ profile: {
38
+ id: 'test-profile',
39
+ target: 'postgres',
40
+ capabilities: {},
41
+ codecs: () => registry,
42
+ },
43
+ lower() {
44
+ return {
45
+ profileId: 'test-profile',
46
+ body: Object.freeze({ sql: '', params: [] }),
47
+ };
48
+ },
49
+ },
50
+ );
51
+ },
52
+ };
53
+ }
54
+
55
+ function createStubTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {
56
+ return {
57
+ kind: 'target',
58
+ id: 'postgres',
59
+ version: '0.0.1',
60
+ familyId: 'sql' as const,
61
+ targetId: 'postgres' as const,
62
+ codecs: () => createCodecRegistry(),
63
+ operationSignatures: () => [],
64
+ parameterizedCodecs: () => [],
65
+ create() {
66
+ return { familyId: 'sql' as const, targetId: 'postgres' as const };
67
+ },
68
+ };
69
+ }
70
+
71
+ function createStubExtensionDescriptor(): SqlRuntimeExtensionDescriptor<'postgres'> {
72
+ const registry = createCodecRegistry();
73
+ registry.register(
74
+ codec({
75
+ typeId: 'pg/uuid@1',
76
+ targetTypes: ['uuid'],
77
+ encode: (value: string) => value,
78
+ decode: (wire: string) => wire,
79
+ }),
80
+ );
81
+
82
+ const operations = [
83
+ {
84
+ forTypeId: 'pg/text@1',
85
+ method: 'example',
86
+ args: [],
87
+ returns: { kind: 'builtin' as const, type: 'string' as const },
88
+ lowering: {
89
+ targetFamily: 'sql' as const,
90
+ strategy: 'function' as const,
91
+ template: 'example({args})',
92
+ },
93
+ },
94
+ ];
95
+
96
+ return {
97
+ kind: 'extension',
98
+ id: 'test-extension',
99
+ version: '0.0.1',
100
+ familyId: 'sql' as const,
101
+ targetId: 'postgres' as const,
102
+ codecs: () => registry,
103
+ operationSignatures: () => operations,
104
+ parameterizedCodecs: () => [],
105
+ create() {
106
+ return {
107
+ familyId: 'sql' as const,
108
+ targetId: 'postgres' as const,
109
+ };
110
+ },
111
+ };
112
+ }
113
+
114
+ describe('createExecutionStack', () => {
115
+ it('defaults driver to undefined and extensions to empty', () => {
116
+ const stack = createExecutionStack({
117
+ target: createStubTargetDescriptor(),
118
+ adapter: createStubAdapterDescriptor(),
119
+ });
120
+
121
+ expect(stack.driver).toBeUndefined();
122
+ expect(stack.extensionPacks).toEqual([]);
123
+ });
124
+
125
+ it('creates an execution context from descriptors-only stack', () => {
126
+ const contract = createTestContract({
127
+ storage: { tables: {} },
128
+ });
129
+
130
+ const context = createExecutionContext({
131
+ contract,
132
+ stack: {
133
+ target: createStubTargetDescriptor(),
134
+ adapter: createStubAdapterDescriptor(),
135
+ extensionPacks: [createStubExtensionDescriptor()],
136
+ },
137
+ }) as ExecutionContext<typeof contract>;
138
+
139
+ expect(context.contract).toBe(contract);
140
+ expect(context.codecs.get('pg/text@1')).toBeDefined();
141
+ expect(context.codecs.get('pg/uuid@1')).toBeDefined();
142
+ expect(context.operations.byType('pg/text@1')).toHaveLength(1);
143
+ expect(context.types).toEqual({});
144
+ });
145
+ });
146
+
147
+ describe('createSqlExecutionStack', () => {
148
+ it('preserves descriptor references and defaults extensions', () => {
149
+ const target = createStubTargetDescriptor();
150
+ const adapter = createStubAdapterDescriptor();
151
+ const stack = createSqlExecutionStack({ target, adapter });
152
+
153
+ expect(stack.target).toBe(target);
154
+ expect(stack.adapter).toBe(adapter);
155
+ expect(stack.extensionPacks).toEqual([]);
156
+ });
157
+
158
+ it('keeps extension packs intact', () => {
159
+ const target = createStubTargetDescriptor();
160
+ const adapter = createStubAdapterDescriptor();
161
+ const extension = createStubExtensionDescriptor();
162
+ const stack = createSqlExecutionStack({ target, adapter, extensionPacks: [extension] });
163
+
164
+ expect(stack.extensionPacks).toEqual([extension]);
165
+ });
166
+ });