@prisma-next/sql-runtime 0.3.0-dev.13 → 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 +102 -64
  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 -59
  153. package/dist/test/utils.d.ts.map +0 -1
  154. package/dist/test/utils.js +0 -24634
  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
@@ -1,5 +1,12 @@
1
- import { createOperationRegistry } from '@prisma-next/operations';
2
- import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
1
+ import type { Contract, ExecutionPlan } from '@prisma-next/contract/types';
2
+ import { coreHash, profileHash } from '@prisma-next/contract/types';
3
+ import {
4
+ type ExecutionStackInstance,
5
+ instantiateExecutionStack,
6
+ type RuntimeDriverInstance,
7
+ type RuntimeExtensionInstance,
8
+ } from '@prisma-next/framework-components/execution';
9
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
3
10
  import type {
4
11
  CodecRegistry,
5
12
  SelectAst,
@@ -8,29 +15,34 @@ import type {
8
15
  } from '@prisma-next/sql-relational-core/ast';
9
16
  import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
10
17
  import { describe, expect, it, vi } from 'vitest';
11
- import type { RuntimeContext } from '../src/sql-context';
18
+ import type {
19
+ SqlRuntimeAdapterDescriptor,
20
+ SqlRuntimeAdapterInstance,
21
+ SqlRuntimeTargetDescriptor,
22
+ } from '../src/sql-context';
23
+ import { createExecutionContext, createSqlExecutionStack } from '../src/sql-context';
12
24
  import { createRuntime } from '../src/sql-runtime';
13
25
 
14
- // Minimal test contract
15
- const testContract: SqlContract<SqlStorage> = {
16
- schemaVersion: '1',
26
+ const testContract: Contract<SqlStorage> = {
17
27
  targetFamily: 'sql',
18
28
  target: 'postgres',
19
- coreHash: 'sha256:test',
29
+ profileHash: profileHash('sha256:test'),
20
30
  models: {},
21
- relations: {},
22
- storage: { tables: {} },
31
+ roots: {},
32
+ storage: { storageHash: coreHash('sha256:test'), tables: {} },
23
33
  extensionPacks: {},
24
34
  capabilities: {},
25
35
  meta: {},
26
- sources: {},
27
- mappings: {
28
- codecTypes: {},
29
- operationTypes: {},
30
- },
31
36
  };
32
37
 
33
- // Create a stub codec registry
38
+ interface DriverExecuteSpies {
39
+ rootExecute: ReturnType<typeof vi.fn>;
40
+ connectionExecute: ReturnType<typeof vi.fn>;
41
+ transactionExecute: ReturnType<typeof vi.fn>;
42
+ }
43
+
44
+ type MockSqlDriver = SqlDriver & { __spies: DriverExecuteSpies };
45
+
34
46
  function createStubCodecs(): CodecRegistry {
35
47
  const registry = createCodecRegistry();
36
48
  registry.register(
@@ -44,7 +56,6 @@ function createStubCodecs(): CodecRegistry {
44
56
  return registry;
45
57
  }
46
58
 
47
- // Create a stub adapter
48
59
  function createStubAdapter() {
49
60
  const codecs = createStubCodecs();
50
61
  return {
@@ -57,6 +68,12 @@ function createStubAdapter() {
57
68
  codecs() {
58
69
  return codecs;
59
70
  },
71
+ readMarkerStatement() {
72
+ return {
73
+ sql: 'select core_hash, profile_hash, contract_json, canonical_version, updated_at, app_tag, meta from prisma_contract.marker where id = $1',
74
+ params: [1],
75
+ };
76
+ },
60
77
  },
61
78
  lower(ast: SelectAst) {
62
79
  return {
@@ -67,37 +84,139 @@ function createStubAdapter() {
67
84
  };
68
85
  }
69
86
 
70
- // Create a mock driver that implements SqlDriver interface
71
- function createMockDriver(): SqlDriver {
72
- const execute = vi.fn().mockImplementation(async function* (_request: SqlExecuteRequest) {
87
+ function createMockDriver(): MockSqlDriver {
88
+ const rootExecute = vi.fn().mockImplementation(async function* (_request: SqlExecuteRequest) {
73
89
  yield { id: 1 };
74
90
  });
91
+ const connectionExecute = vi.fn().mockImplementation(async function* (
92
+ _request: SqlExecuteRequest,
93
+ ) {
94
+ yield { id: 2 };
95
+ });
96
+ const transactionExecute = vi.fn().mockImplementation(async function* (
97
+ _request: SqlExecuteRequest,
98
+ ) {
99
+ yield { id: 3 };
100
+ });
75
101
 
76
- return {
77
- connect: vi.fn().mockResolvedValue(undefined),
78
- execute,
79
- query: vi.fn().mockResolvedValue({ rows: [], rowCount: 0 }),
102
+ const query = vi.fn().mockResolvedValue({ rows: [], rowCount: 0 });
103
+
104
+ const transaction = {
105
+ execute: transactionExecute,
106
+ query,
107
+ commit: vi.fn().mockResolvedValue(undefined),
108
+ rollback: vi.fn().mockResolvedValue(undefined),
109
+ };
110
+
111
+ const connection = {
112
+ execute: connectionExecute,
113
+ query,
114
+ release: vi.fn().mockResolvedValue(undefined),
115
+ beginTransaction: vi.fn().mockResolvedValue(transaction),
116
+ };
117
+
118
+ const driver: SqlDriver = {
119
+ execute: rootExecute,
120
+ query,
121
+ connect: vi.fn().mockImplementation(async (_binding?: undefined) => undefined),
122
+ acquireConnection: vi.fn().mockResolvedValue(connection),
80
123
  close: vi.fn().mockResolvedValue(undefined),
81
124
  };
125
+
126
+ return Object.assign(driver, {
127
+ __spies: {
128
+ rootExecute,
129
+ connectionExecute,
130
+ transactionExecute,
131
+ },
132
+ });
133
+ }
134
+
135
+ function createTestTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {
136
+ return {
137
+ kind: 'target',
138
+ id: 'postgres',
139
+ version: '0.0.1',
140
+ familyId: 'sql' as const,
141
+ targetId: 'postgres' as const,
142
+ codecs: () => createCodecRegistry(),
143
+ parameterizedCodecs: () => [],
144
+ create() {
145
+ return { familyId: 'sql' as const, targetId: 'postgres' as const };
146
+ },
147
+ };
82
148
  }
83
149
 
84
- // Create a test runtime context
85
- function createTestContext(contract: SqlContract<SqlStorage>): RuntimeContext<typeof contract> {
150
+ function createTestAdapterDescriptor(
151
+ adapter: ReturnType<typeof createStubAdapter>,
152
+ ): SqlRuntimeAdapterDescriptor<'postgres'> {
153
+ const codecRegistry = adapter.profile.codecs();
154
+ return {
155
+ kind: 'adapter',
156
+ id: 'test-adapter',
157
+ version: '0.0.1',
158
+ familyId: 'sql' as const,
159
+ targetId: 'postgres' as const,
160
+ codecs: () => codecRegistry,
161
+ parameterizedCodecs: () => [],
162
+ create() {
163
+ return Object.assign(
164
+ { familyId: 'sql' as const, targetId: 'postgres' as const },
165
+ adapter,
166
+ ) as SqlRuntimeAdapterInstance<'postgres'>;
167
+ },
168
+ };
169
+ }
170
+
171
+ function createTestSetup() {
86
172
  const adapter = createStubAdapter();
173
+ const driver = createMockDriver();
174
+
175
+ const targetDescriptor = createTestTargetDescriptor();
176
+ const adapterDescriptor = createTestAdapterDescriptor(adapter);
177
+
178
+ const stack = createSqlExecutionStack({
179
+ target: targetDescriptor,
180
+ adapter: adapterDescriptor,
181
+ extensionPacks: [],
182
+ });
183
+ type SqlTestStackInstance = ExecutionStackInstance<
184
+ 'sql',
185
+ 'postgres',
186
+ SqlRuntimeAdapterInstance<'postgres'>,
187
+ RuntimeDriverInstance<'sql', 'postgres'>,
188
+ RuntimeExtensionInstance<'sql', 'postgres'>
189
+ >;
190
+ const stackInstance = instantiateExecutionStack(stack) as SqlTestStackInstance;
191
+
192
+ const context = createExecutionContext({
193
+ contract: testContract,
194
+ stack: { target: targetDescriptor, adapter: adapterDescriptor, extensionPacks: [] },
195
+ });
196
+
197
+ return { stackInstance, context, driver };
198
+ }
199
+
200
+ function createRawExecutionPlan<Row = Record<string, unknown>>(): ExecutionPlan<Row> {
87
201
  return {
88
- contract,
89
- adapter,
90
- codecs: adapter.profile.codecs(),
91
- operations: createOperationRegistry(),
202
+ sql: 'select 1',
203
+ params: [],
204
+ meta: {
205
+ target: testContract.target,
206
+ targetFamily: testContract.targetFamily,
207
+ storageHash: testContract.storage.storageHash,
208
+ lane: 'raw',
209
+ paramDescriptors: [],
210
+ },
92
211
  };
93
212
  }
94
213
 
95
214
  describe('createRuntime', () => {
96
- it('creates runtime with valid options', () => {
97
- const context = createTestContext(testContract);
98
- const driver = createMockDriver();
215
+ it('creates runtime with context and driver', () => {
216
+ const { stackInstance, context, driver } = createTestSetup();
99
217
 
100
218
  const runtime = createRuntime({
219
+ stackInstance,
101
220
  context,
102
221
  driver,
103
222
  verify: { mode: 'onFirstUse', requireMarker: false },
@@ -106,50 +225,102 @@ describe('createRuntime', () => {
106
225
  expect(runtime).toBeDefined();
107
226
  expect(runtime.execute).toBeDefined();
108
227
  expect(runtime.telemetry).toBeDefined();
109
- expect(runtime.operations).toBeDefined();
110
228
  expect(runtime.close).toBeDefined();
111
229
  });
112
230
 
113
- it('returns operations registry', () => {
114
- const context = createTestContext(testContract);
115
- const driver = createMockDriver();
231
+ it('returns null telemetry when no events', () => {
232
+ const { stackInstance, context, driver } = createTestSetup();
116
233
 
117
234
  const runtime = createRuntime({
235
+ stackInstance,
118
236
  context,
119
237
  driver,
120
238
  verify: { mode: 'onFirstUse', requireMarker: false },
121
239
  });
122
240
 
123
- const ops = runtime.operations();
124
- expect(ops).toBeDefined();
125
- expect(ops.byType).toBeDefined();
241
+ expect(runtime.telemetry()).toBeNull();
126
242
  });
127
243
 
128
- it('returns null telemetry when no events', () => {
129
- const context = createTestContext(testContract);
130
- const driver = createMockDriver();
244
+ it('closes runtime and driver', async () => {
245
+ const { stackInstance, context, driver } = createTestSetup();
131
246
 
132
247
  const runtime = createRuntime({
248
+ stackInstance,
133
249
  context,
134
250
  driver,
135
251
  verify: { mode: 'onFirstUse', requireMarker: false },
136
252
  });
137
253
 
138
- // Before any execution, telemetry should be null
139
- expect(runtime.telemetry()).toBeNull();
254
+ await runtime.close();
255
+ expect(driver.close).toHaveBeenCalled();
140
256
  });
141
257
 
142
- it('closes runtime', async () => {
143
- const context = createTestContext(testContract);
144
- const driver = createMockDriver();
258
+ it('validates codec registry at startup when verify mode is startup', () => {
259
+ const { stackInstance, context, driver } = createTestSetup();
145
260
 
146
261
  const runtime = createRuntime({
262
+ stackInstance,
263
+ context,
264
+ driver,
265
+ verify: { mode: 'startup', requireMarker: false },
266
+ });
267
+
268
+ expect(runtime).toBeDefined();
269
+ });
270
+
271
+ it('uses acquired connection queryable for connection.execute', async () => {
272
+ const { stackInstance, context, driver } = createTestSetup();
273
+ const runtime = createRuntime({
274
+ stackInstance,
147
275
  context,
148
276
  driver,
149
277
  verify: { mode: 'onFirstUse', requireMarker: false },
150
278
  });
151
279
 
152
- await runtime.close();
153
- expect(driver.close).toHaveBeenCalled();
280
+ const connection = await runtime.connection();
281
+ await connection.execute(createRawExecutionPlan()).toArray();
282
+
283
+ expect(driver.__spies.connectionExecute).toHaveBeenCalledTimes(1);
284
+ expect(driver.__spies.transactionExecute).not.toHaveBeenCalled();
285
+ expect(driver.__spies.rootExecute).not.toHaveBeenCalled();
286
+
287
+ await connection.release();
288
+ });
289
+
290
+ it('uses transaction queryable for transaction.execute', async () => {
291
+ const { stackInstance, context, driver } = createTestSetup();
292
+ const runtime = createRuntime({
293
+ stackInstance,
294
+ context,
295
+ driver,
296
+ verify: { mode: 'onFirstUse', requireMarker: false },
297
+ });
298
+
299
+ const connection = await runtime.connection();
300
+ const transaction = await connection.transaction();
301
+ await transaction.execute(createRawExecutionPlan()).toArray();
302
+
303
+ expect(driver.__spies.transactionExecute).toHaveBeenCalledTimes(1);
304
+ expect(driver.__spies.connectionExecute).not.toHaveBeenCalled();
305
+ expect(driver.__spies.rootExecute).not.toHaveBeenCalled();
306
+
307
+ await transaction.rollback();
308
+ await connection.release();
309
+ });
310
+
311
+ it('keeps root execute on driver queryable for runtime.execute', async () => {
312
+ const { stackInstance, context, driver } = createTestSetup();
313
+ const runtime = createRuntime({
314
+ stackInstance,
315
+ context,
316
+ driver,
317
+ verify: { mode: 'onFirstUse', requireMarker: false },
318
+ });
319
+
320
+ await runtime.execute(createRawExecutionPlan()).toArray();
321
+
322
+ expect(driver.__spies.rootExecute).toHaveBeenCalledTimes(1);
323
+ expect(driver.__spies.connectionExecute).not.toHaveBeenCalled();
324
+ expect(driver.__spies.transactionExecute).not.toHaveBeenCalled();
154
325
  });
155
326
  });
package/test/utils.ts CHANGED
@@ -1,5 +1,12 @@
1
- import type { ExecutionPlan, ResultType } from '@prisma-next/contract/types';
2
- import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
1
+ import type { Contract, ExecutionPlan, ResultType } from '@prisma-next/contract/types';
2
+ import { coreHash, profileHash } from '@prisma-next/contract/types';
3
+ import {
4
+ instantiateExecutionStack,
5
+ type RuntimeDriverDescriptor,
6
+ } from '@prisma-next/framework-components/execution';
7
+ import { builtinGeneratorIds } from '@prisma-next/ids';
8
+ import { generateId } from '@prisma-next/ids/runtime';
9
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
3
10
  import type { Adapter, LoweredStatement, SelectAst } from '@prisma-next/sql-relational-core/ast';
4
11
  import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
5
12
  import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
@@ -7,18 +14,29 @@ import { collectAsync, drainAsyncIterable } from '@prisma-next/test-utils';
7
14
  import type { Client } from 'pg';
8
15
  import type { SqlStatement } from '../src/exports';
9
16
  import {
17
+ createExecutionContext,
10
18
  type createRuntime,
11
- createRuntimeContext,
19
+ createSqlExecutionStack,
12
20
  ensureSchemaStatement,
13
21
  ensureTableStatement,
14
22
  writeContractMarker,
15
23
  } from '../src/exports';
16
24
  import type {
17
- RuntimeContext,
25
+ ExecutionContext,
26
+ SqlRuntimeAdapterDescriptor,
18
27
  SqlRuntimeAdapterInstance,
28
+ SqlRuntimeDriverInstance,
19
29
  SqlRuntimeExtensionDescriptor,
30
+ SqlRuntimeTargetDescriptor,
20
31
  } from '../src/sql-context';
21
32
 
33
+ function createTestMutationDefaultGenerators() {
34
+ return builtinGeneratorIds.map((id) => ({
35
+ id,
36
+ generate: (params?: Record<string, unknown>) => generateId(params ? { id, params } : { id }),
37
+ }));
38
+ }
39
+
22
40
  /**
23
41
  * Executes a plan and collects all results into an array.
24
42
  * This helper DRYs up the common pattern of executing plans in tests.
@@ -60,7 +78,7 @@ export async function executeStatement(client: Client, statement: SqlStatement):
60
78
  */
61
79
  export async function setupTestDatabase(
62
80
  client: Client,
63
- contract: SqlContract<SqlStorage>,
81
+ contract: Contract<SqlStorage>,
64
82
  setupFn: (client: Client) => Promise<void>,
65
83
  ): Promise<void> {
66
84
  await client.query('drop schema if exists prisma_contract cascade');
@@ -71,8 +89,8 @@ export async function setupTestDatabase(
71
89
  await executeStatement(client, ensureSchemaStatement);
72
90
  await executeStatement(client, ensureTableStatement);
73
91
  const write = writeContractMarker({
74
- coreHash: contract.coreHash,
75
- profileHash: contract.profileHash ?? contract.coreHash,
92
+ storageHash: contract.storage.storageHash,
93
+ profileHash: contract.profileHash,
76
94
  contractJson: contract,
77
95
  canonicalVersion: 1,
78
96
  });
@@ -85,11 +103,11 @@ export async function setupTestDatabase(
85
103
  */
86
104
  export async function writeTestContractMarker(
87
105
  client: Client,
88
- contract: SqlContract<SqlStorage>,
106
+ contract: Contract<SqlStorage>,
89
107
  ): Promise<void> {
90
108
  const write = writeContractMarker({
91
- coreHash: contract.coreHash,
92
- profileHash: contract.profileHash ?? contract.coreHash,
109
+ storageHash: contract.storage.storageHash,
110
+ profileHash: contract.profileHash,
93
111
  contractJson: contract,
94
112
  canonicalVersion: 1,
95
113
  });
@@ -98,56 +116,40 @@ export async function writeTestContractMarker(
98
116
 
99
117
  /**
100
118
  * Creates a test adapter descriptor from a raw adapter.
101
- * This wraps the adapter in a descriptor for descriptor-first context creation in tests.
102
- * The adapter instance IS an Adapter (via intersection), with identity properties added.
119
+ * Wraps the adapter in an SqlRuntimeAdapterDescriptor with static contributions
120
+ * derived from the adapter's codec registry.
103
121
  */
104
- function createTestAdapterDescriptor(
105
- adapter: Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
106
- ): {
107
- readonly kind: 'adapter';
108
- readonly id: string;
109
- readonly version: string;
110
- readonly familyId: 'sql';
111
- readonly targetId: 'postgres';
112
- create(): SqlRuntimeAdapterInstance<'postgres'>;
113
- } {
122
+ export function createTestAdapterDescriptor(
123
+ adapter: Adapter<SelectAst, Contract<SqlStorage>, LoweredStatement>,
124
+ ): SqlRuntimeAdapterDescriptor<'postgres'> {
125
+ const codecRegistry = adapter.profile.codecs();
114
126
  return {
115
127
  kind: 'adapter' as const,
116
128
  id: 'test-adapter',
117
129
  version: '0.0.1',
118
130
  familyId: 'sql' as const,
119
131
  targetId: 'postgres' as const,
132
+ codecs: () => codecRegistry,
133
+ parameterizedCodecs: () => [],
134
+ mutationDefaultGenerators: createTestMutationDefaultGenerators,
120
135
  create(): SqlRuntimeAdapterInstance<'postgres'> {
121
- // Return an object that combines identity properties with the adapter's methods
122
- return Object.assign(
123
- {
124
- familyId: 'sql' as const,
125
- targetId: 'postgres' as const,
126
- },
127
- adapter,
128
- );
136
+ return Object.assign({ familyId: 'sql' as const, targetId: 'postgres' as const }, adapter);
129
137
  },
130
138
  };
131
139
  }
132
140
 
133
141
  /**
134
- * Creates a test target descriptor.
135
- * This is a minimal descriptor for descriptor-first context creation in tests.
142
+ * Creates a test target descriptor with empty static contributions.
136
143
  */
137
- function createTestTargetDescriptor(): {
138
- readonly kind: 'target';
139
- readonly id: string;
140
- readonly version: string;
141
- readonly familyId: 'sql';
142
- readonly targetId: 'postgres';
143
- create(): { readonly familyId: 'sql'; readonly targetId: 'postgres' };
144
- } {
144
+ export function createTestTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {
145
145
  return {
146
146
  kind: 'target' as const,
147
147
  id: 'postgres',
148
148
  version: '0.0.1',
149
149
  familyId: 'sql' as const,
150
150
  targetId: 'postgres' as const,
151
+ codecs: () => createCodecRegistry(),
152
+ parameterizedCodecs: () => [],
151
153
  create() {
152
154
  return { familyId: 'sql' as const, targetId: 'postgres' as const };
153
155
  },
@@ -155,25 +157,46 @@ function createTestTargetDescriptor(): {
155
157
  }
156
158
 
157
159
  /**
158
- * Creates a runtime context with standard test configuration.
160
+ * Creates an ExecutionContext for testing.
159
161
  * This helper DRYs up the common pattern of context creation in tests.
160
162
  *
161
163
  * Accepts a raw adapter and optional extension descriptors, wrapping the
162
164
  * adapter in a descriptor internally for descriptor-first context creation.
163
165
  */
164
- export function createTestContext<TContract extends SqlContract<SqlStorage>>(
166
+ export function createTestContext<TContract extends Contract<SqlStorage>>(
165
167
  contract: TContract,
166
- adapter: Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
168
+ adapter: Adapter<SelectAst, Contract<SqlStorage>, LoweredStatement>,
167
169
  options?: {
168
170
  extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;
169
171
  },
170
- ): RuntimeContext<TContract> {
171
- return createRuntimeContext<TContract, 'postgres'>({
172
+ ): ExecutionContext<TContract> {
173
+ return createExecutionContext({
172
174
  contract,
175
+ stack: {
176
+ target: createTestTargetDescriptor(),
177
+ adapter: createTestAdapterDescriptor(adapter),
178
+ extensionPacks: options?.extensionPacks ?? [],
179
+ },
180
+ });
181
+ }
182
+
183
+ export function createTestStackInstance(options?: {
184
+ extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;
185
+ driver?: RuntimeDriverDescriptor<
186
+ 'sql',
187
+ 'postgres',
188
+ unknown,
189
+ SqlRuntimeDriverInstance<'postgres'>
190
+ >;
191
+ }) {
192
+ const stack = createSqlExecutionStack({
173
193
  target: createTestTargetDescriptor(),
174
- adapter: createTestAdapterDescriptor(adapter),
194
+ adapter: createTestAdapterDescriptor(createStubAdapter()),
195
+ driver: options?.driver,
175
196
  extensionPacks: options?.extensionPacks ?? [],
176
197
  });
198
+
199
+ return instantiateExecutionStack(stack);
177
200
  }
178
201
 
179
202
  /**
@@ -183,7 +206,7 @@ export function createTestContext<TContract extends SqlContract<SqlStorage>>(
183
206
  * The stub adapter includes simple codecs for common test types (pg/int4@1, pg/text@1, pg/timestamptz@1)
184
207
  * to enable type inference in tests without requiring the postgres adapter package.
185
208
  */
186
- export function createStubAdapter(): Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement> {
209
+ export function createStubAdapter(): Adapter<SelectAst, Contract<SqlStorage>, LoweredStatement> {
187
210
  const codecRegistry = createCodecRegistry();
188
211
 
189
212
  // Register stub codecs for common test types
@@ -212,8 +235,7 @@ export function createStubAdapter(): Adapter<SelectAst, SqlContract<SqlStorage>,
212
235
  typeId: 'pg/timestamptz@1',
213
236
  targetTypes: ['timestamptz'],
214
237
  encode: (value: string | Date) => (value instanceof Date ? value.toISOString() : value),
215
- decode: (wire: string | Date) =>
216
- typeof wire === 'string' ? wire : wire instanceof Date ? wire.toISOString() : String(wire),
238
+ decode: (wire: string | Date) => (wire instanceof Date ? wire : new Date(wire)),
217
239
  }),
218
240
  );
219
241
 
@@ -225,8 +247,14 @@ export function createStubAdapter(): Adapter<SelectAst, SqlContract<SqlStorage>,
225
247
  codecs() {
226
248
  return codecRegistry;
227
249
  },
250
+ readMarkerStatement() {
251
+ return {
252
+ sql: 'select core_hash, profile_hash, contract_json, canonical_version, updated_at, app_tag, meta from prisma_contract.marker where id = $1',
253
+ params: [1],
254
+ };
255
+ },
228
256
  },
229
- lower(ast: SelectAst, ctx: { contract: SqlContract<SqlStorage>; params?: readonly unknown[] }) {
257
+ lower(ast: SelectAst, ctx: { contract: Contract<SqlStorage>; params?: readonly unknown[] }) {
230
258
  const sqlText = JSON.stringify(ast);
231
259
  return {
232
260
  profileId: this.profile.id,
@@ -236,20 +264,30 @@ export function createStubAdapter(): Adapter<SelectAst, SqlContract<SqlStorage>,
236
264
  };
237
265
  }
238
266
 
239
- /**
240
- * Creates a valid test contract without using validateContract.
241
- * Ensures mappings are present and returns the contract with proper typing.
242
- * This helper allows tests to create contracts without depending on sql-query.
243
- */
244
- export function createTestContract<T extends SqlContract<SqlStorage>>(contract: T): T {
245
- // Ensure mappings are present
246
- if (!contract.mappings) {
247
- return {
248
- ...contract,
249
- mappings: { codecTypes: {}, operationTypes: {} },
250
- } as T;
251
- }
252
- return contract;
267
+ export function createTestContract(
268
+ contract: Partial<Omit<Contract<SqlStorage>, 'profileHash' | 'storage'>> & {
269
+ storageHash?: string;
270
+ profileHash?: string;
271
+ storage?: Omit<SqlStorage, 'storageHash'>;
272
+ },
273
+ ): Contract<SqlStorage> {
274
+ const { execution, ...rest } = contract;
275
+ const storageHashValue = coreHash(rest['storageHash'] ?? 'sha256:testcore');
276
+
277
+ return {
278
+ target: rest['target'] ?? 'postgres',
279
+ targetFamily: rest['targetFamily'] ?? 'sql',
280
+ storage: rest['storage']
281
+ ? { ...rest['storage'], storageHash: storageHashValue }
282
+ : { storageHash: storageHashValue, tables: {} },
283
+ models: rest['models'] ?? {},
284
+ roots: rest['roots'] ?? {},
285
+ capabilities: rest['capabilities'] ?? {},
286
+ extensionPacks: rest['extensionPacks'] ?? {},
287
+ meta: rest['meta'] ?? {},
288
+ ...(execution ? { execution } : {}),
289
+ profileHash: profileHash(rest['profileHash'] ?? 'sha256:testprofile'),
290
+ };
253
291
  }
254
292
 
255
293
  // Re-export generic utilities from test-utils