@prisma-next/sql-runtime 0.3.0-dev.4 → 0.3.0-dev.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/README.md +116 -26
  2. package/dist/exports-C8hi0N-a.mjs +622 -0
  3. package/dist/exports-C8hi0N-a.mjs.map +1 -0
  4. package/dist/index-SlQIrV_t.d.mts +131 -0
  5. package/dist/index-SlQIrV_t.d.mts.map +1 -0
  6. package/dist/index.d.mts +2 -0
  7. package/dist/index.mjs +3 -0
  8. package/dist/test/utils.d.mts +82 -0
  9. package/dist/test/utils.d.mts.map +1 -0
  10. package/dist/test/utils.mjs +212 -0
  11. package/dist/test/utils.mjs.map +1 -0
  12. package/package.json +35 -26
  13. package/src/codecs/decoding.ts +221 -0
  14. package/src/codecs/encoding.ts +89 -0
  15. package/src/codecs/json-schema-validation.ts +61 -0
  16. package/src/codecs/validation.ts +67 -0
  17. package/src/exports/index.ts +45 -0
  18. package/src/lower-sql-plan.ts +32 -0
  19. package/src/sql-context.ts +443 -0
  20. package/src/sql-family-adapter.ts +47 -0
  21. package/src/sql-marker.ts +105 -0
  22. package/src/sql-runtime.ts +232 -0
  23. package/test/async-iterable-result.test.ts +144 -0
  24. package/test/context.types.test-d.ts +68 -0
  25. package/test/execution-stack.test.ts +166 -0
  26. package/test/json-schema-validation.test.ts +653 -0
  27. package/test/parameterized-types.test.ts +539 -0
  28. package/test/sql-context.test.ts +392 -0
  29. package/test/sql-family-adapter.test.ts +87 -0
  30. package/test/sql-runtime.test.ts +241 -0
  31. package/test/utils.ts +292 -0
  32. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
  33. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
  34. package/dist/amcheck-24VY6X5V.js +0 -13
  35. package/dist/amcheck-24VY6X5V.js.map +0 -1
  36. package/dist/bloom-VS74NLHT.js +0 -13
  37. package/dist/bloom-VS74NLHT.js.map +0 -1
  38. package/dist/btree_gin-WBC4EAAI.js +0 -13
  39. package/dist/btree_gin-WBC4EAAI.js.map +0 -1
  40. package/dist/btree_gist-UNC6QD3M.js +0 -13
  41. package/dist/btree_gist-UNC6QD3M.js.map +0 -1
  42. package/dist/chunk-3KTOEDFX.js +0 -49
  43. package/dist/chunk-3KTOEDFX.js.map +0 -1
  44. package/dist/chunk-47DZBRQC.js +0 -1280
  45. package/dist/chunk-47DZBRQC.js.map +0 -1
  46. package/dist/chunk-52N6AFZM.js +0 -133
  47. package/dist/chunk-52N6AFZM.js.map +0 -1
  48. package/dist/chunk-7D4SUZUM.js +0 -38
  49. package/dist/chunk-7D4SUZUM.js.map +0 -1
  50. package/dist/chunk-C6I3V3DM.js +0 -455
  51. package/dist/chunk-C6I3V3DM.js.map +0 -1
  52. package/dist/chunk-ECWIHLAT.js +0 -37
  53. package/dist/chunk-ECWIHLAT.js.map +0 -1
  54. package/dist/chunk-EI626SDC.js +0 -105
  55. package/dist/chunk-EI626SDC.js.map +0 -1
  56. package/dist/chunk-UKKOYUGL.js +0 -578
  57. package/dist/chunk-UKKOYUGL.js.map +0 -1
  58. package/dist/chunk-XPLNMXQV.js +0 -1537
  59. package/dist/chunk-XPLNMXQV.js.map +0 -1
  60. package/dist/citext-T7MXGUY7.js +0 -13
  61. package/dist/citext-T7MXGUY7.js.map +0 -1
  62. package/dist/client-5FENX6AW.js +0 -299
  63. package/dist/client-5FENX6AW.js.map +0 -1
  64. package/dist/cube-TFDQBZCI.js +0 -13
  65. package/dist/cube-TFDQBZCI.js.map +0 -1
  66. package/dist/dict_int-AEUOPGWP.js +0 -13
  67. package/dist/dict_int-AEUOPGWP.js.map +0 -1
  68. package/dist/dict_xsyn-DAAYX3FL.js +0 -13
  69. package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
  70. package/dist/dist-AQ3LWXOX.js +0 -570
  71. package/dist/dist-AQ3LWXOX.js.map +0 -1
  72. package/dist/dist-LBVX6BJW.js +0 -189
  73. package/dist/dist-LBVX6BJW.js.map +0 -1
  74. package/dist/dist-WLKUVDN2.js +0 -5127
  75. package/dist/dist-WLKUVDN2.js.map +0 -1
  76. package/dist/earthdistance-KIGTF4LE.js +0 -13
  77. package/dist/earthdistance-KIGTF4LE.js.map +0 -1
  78. package/dist/file_fdw-5N55UP6I.js +0 -13
  79. package/dist/file_fdw-5N55UP6I.js.map +0 -1
  80. package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
  81. package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
  82. package/dist/hstore-YX726NKN.js +0 -13
  83. package/dist/hstore-YX726NKN.js.map +0 -1
  84. package/dist/http-exception-FZY2H4OF.js +0 -8
  85. package/dist/http-exception-FZY2H4OF.js.map +0 -1
  86. package/dist/index.d.ts +0 -29
  87. package/dist/index.js +0 -30
  88. package/dist/index.js.map +0 -1
  89. package/dist/intarray-NKVXNO2D.js +0 -13
  90. package/dist/intarray-NKVXNO2D.js.map +0 -1
  91. package/dist/isn-FTEMJGEV.js +0 -13
  92. package/dist/isn-FTEMJGEV.js.map +0 -1
  93. package/dist/lo-DB7L4NGI.js +0 -13
  94. package/dist/lo-DB7L4NGI.js.map +0 -1
  95. package/dist/logger-WQ7SHNDD.js +0 -68
  96. package/dist/logger-WQ7SHNDD.js.map +0 -1
  97. package/dist/ltree-Z32TZT6W.js +0 -13
  98. package/dist/ltree-Z32TZT6W.js.map +0 -1
  99. package/dist/nodefs-NM46ACH7.js +0 -31
  100. package/dist/nodefs-NM46ACH7.js.map +0 -1
  101. package/dist/opfs-ahp-NJO33LVZ.js +0 -332
  102. package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
  103. package/dist/pageinspect-YP3IZR4X.js +0 -13
  104. package/dist/pageinspect-YP3IZR4X.js.map +0 -1
  105. package/dist/pg_buffercache-7TD5J2FB.js +0 -13
  106. package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
  107. package/dist/pg_dump-SG4KYBUB.js +0 -2492
  108. package/dist/pg_dump-SG4KYBUB.js.map +0 -1
  109. package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
  110. package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
  111. package/dist/pg_surgery-J2MUEWEP.js +0 -13
  112. package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
  113. package/dist/pg_trgm-7VNQOYS6.js +0 -13
  114. package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
  115. package/dist/pg_visibility-TTSIPHFL.js +0 -13
  116. package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
  117. package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
  118. package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
  119. package/dist/proxy-signals-GUDAMDHV.js +0 -39
  120. package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
  121. package/dist/seg-IYVDLE4O.js +0 -13
  122. package/dist/seg-IYVDLE4O.js.map +0 -1
  123. package/dist/sql-runtime-DgEbg2OP.d.ts +0 -109
  124. package/dist/tablefunc-EF4RCS7S.js +0 -13
  125. package/dist/tablefunc-EF4RCS7S.js.map +0 -1
  126. package/dist/tcn-3VT5BQYW.js +0 -13
  127. package/dist/tcn-3VT5BQYW.js.map +0 -1
  128. package/dist/test/utils.d.ts +0 -64
  129. package/dist/test/utils.js +0 -24634
  130. package/dist/test/utils.js.map +0 -1
  131. package/dist/tiny-CW6F4GX6.js +0 -10
  132. package/dist/tiny-CW6F4GX6.js.map +0 -1
  133. package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
  134. package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
  135. package/dist/tsm_system_time-76WEIMBG.js +0 -13
  136. package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
  137. package/dist/unaccent-7RYF3R64.js +0 -13
  138. package/dist/unaccent-7RYF3R64.js.map +0 -1
  139. package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
  140. package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
  141. package/dist/uuid_ossp-4ETE4FPE.js +0 -13
  142. package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
  143. package/dist/vector-74GPNV7V.js +0 -13
  144. package/dist/vector-74GPNV7V.js.map +0 -1
@@ -0,0 +1,241 @@
1
+ import { coreHash } from '@prisma-next/contract/types';
2
+ import type { ExecutionStackInstance } from '@prisma-next/core-execution-plane/stack';
3
+ import { instantiateExecutionStack } from '@prisma-next/core-execution-plane/stack';
4
+ import type {
5
+ RuntimeDriverInstance,
6
+ RuntimeExtensionInstance,
7
+ } from '@prisma-next/core-execution-plane/types';
8
+ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
9
+ import type {
10
+ CodecRegistry,
11
+ SelectAst,
12
+ SqlDriver,
13
+ SqlExecuteRequest,
14
+ } from '@prisma-next/sql-relational-core/ast';
15
+ import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
16
+ import { describe, expect, it, vi } from 'vitest';
17
+ import type {
18
+ SqlRuntimeAdapterDescriptor,
19
+ SqlRuntimeAdapterInstance,
20
+ SqlRuntimeTargetDescriptor,
21
+ } from '../src/sql-context';
22
+ import { createExecutionContext, createSqlExecutionStack } from '../src/sql-context';
23
+ import { createRuntime } from '../src/sql-runtime';
24
+
25
+ const testContract: SqlContract<SqlStorage> = {
26
+ schemaVersion: '1',
27
+ targetFamily: 'sql',
28
+ target: 'postgres',
29
+ storageHash: coreHash('sha256:test'),
30
+ models: {},
31
+ relations: {},
32
+ storage: { tables: {} },
33
+ extensionPacks: {},
34
+ capabilities: {},
35
+ meta: {},
36
+ sources: {},
37
+ mappings: {
38
+ codecTypes: {},
39
+ operationTypes: {},
40
+ },
41
+ };
42
+
43
+ function createStubCodecs(): CodecRegistry {
44
+ const registry = createCodecRegistry();
45
+ registry.register(
46
+ codec({
47
+ typeId: 'pg/int4@1',
48
+ targetTypes: ['int4'],
49
+ encode: (v: number) => v,
50
+ decode: (w: number) => w,
51
+ }),
52
+ );
53
+ return registry;
54
+ }
55
+
56
+ function createStubAdapter() {
57
+ const codecs = createStubCodecs();
58
+ return {
59
+ familyId: 'sql' as const,
60
+ targetId: 'postgres' as const,
61
+ profile: {
62
+ id: 'test-profile',
63
+ target: 'postgres',
64
+ capabilities: {},
65
+ codecs() {
66
+ return codecs;
67
+ },
68
+ },
69
+ lower(ast: SelectAst) {
70
+ return {
71
+ profileId: 'test-profile',
72
+ body: Object.freeze({ sql: JSON.stringify(ast), params: [] }),
73
+ };
74
+ },
75
+ };
76
+ }
77
+
78
+ function createMockDriver(): SqlDriver {
79
+ const queryable = {
80
+ execute: vi.fn().mockImplementation(async function* (_request: SqlExecuteRequest) {
81
+ yield { id: 1 };
82
+ }),
83
+ query: vi.fn().mockResolvedValue({ rows: [], rowCount: 0 }),
84
+ };
85
+
86
+ return {
87
+ ...queryable,
88
+ connect: vi.fn().mockImplementation(async (_binding?: undefined) => undefined),
89
+ acquireConnection: vi.fn().mockResolvedValue({
90
+ ...queryable,
91
+ release: vi.fn().mockResolvedValue(undefined),
92
+ beginTransaction: vi.fn().mockResolvedValue({
93
+ ...queryable,
94
+ commit: vi.fn().mockResolvedValue(undefined),
95
+ rollback: vi.fn().mockResolvedValue(undefined),
96
+ }),
97
+ }),
98
+ close: vi.fn().mockResolvedValue(undefined),
99
+ };
100
+ }
101
+
102
+ function createTestTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {
103
+ return {
104
+ kind: 'target',
105
+ id: 'postgres',
106
+ version: '0.0.1',
107
+ familyId: 'sql' as const,
108
+ targetId: 'postgres' as const,
109
+ codecs: () => createCodecRegistry(),
110
+ operationSignatures: () => [],
111
+ parameterizedCodecs: () => [],
112
+ create() {
113
+ return { familyId: 'sql' as const, targetId: 'postgres' as const };
114
+ },
115
+ };
116
+ }
117
+
118
+ function createTestAdapterDescriptor(
119
+ adapter: ReturnType<typeof createStubAdapter>,
120
+ ): SqlRuntimeAdapterDescriptor<'postgres'> {
121
+ const codecRegistry = adapter.profile.codecs();
122
+ return {
123
+ kind: 'adapter',
124
+ id: 'test-adapter',
125
+ version: '0.0.1',
126
+ familyId: 'sql' as const,
127
+ targetId: 'postgres' as const,
128
+ codecs: () => codecRegistry,
129
+ operationSignatures: () => [],
130
+ parameterizedCodecs: () => [],
131
+ create() {
132
+ return Object.assign(
133
+ { familyId: 'sql' as const, targetId: 'postgres' as const },
134
+ adapter,
135
+ ) as SqlRuntimeAdapterInstance<'postgres'>;
136
+ },
137
+ };
138
+ }
139
+
140
+ function createTestSetup() {
141
+ const adapter = createStubAdapter();
142
+ const driver = createMockDriver();
143
+
144
+ const targetDescriptor = createTestTargetDescriptor();
145
+ const adapterDescriptor = createTestAdapterDescriptor(adapter);
146
+
147
+ const stack = createSqlExecutionStack({
148
+ target: targetDescriptor,
149
+ adapter: adapterDescriptor,
150
+ extensionPacks: [],
151
+ });
152
+ type SqlTestStackInstance = ExecutionStackInstance<
153
+ 'sql',
154
+ 'postgres',
155
+ SqlRuntimeAdapterInstance<'postgres'>,
156
+ RuntimeDriverInstance<'sql', 'postgres'>,
157
+ RuntimeExtensionInstance<'sql', 'postgres'>
158
+ >;
159
+ const stackInstance = instantiateExecutionStack(stack) as SqlTestStackInstance;
160
+
161
+ const context = createExecutionContext({
162
+ contract: testContract,
163
+ stack: { target: targetDescriptor, adapter: adapterDescriptor, extensionPacks: [] },
164
+ });
165
+
166
+ return { stackInstance, context, driver };
167
+ }
168
+
169
+ describe('createRuntime', () => {
170
+ it('creates runtime with context and driver', () => {
171
+ const { stackInstance, context, driver } = createTestSetup();
172
+
173
+ const runtime = createRuntime({
174
+ stackInstance,
175
+ context,
176
+ driver,
177
+ verify: { mode: 'onFirstUse', requireMarker: false },
178
+ });
179
+
180
+ expect(runtime).toBeDefined();
181
+ expect(runtime.execute).toBeDefined();
182
+ expect(runtime.telemetry).toBeDefined();
183
+ expect(runtime.operations).toBeDefined();
184
+ expect(runtime.close).toBeDefined();
185
+ });
186
+
187
+ it('returns operations registry', () => {
188
+ const { stackInstance, context, driver } = createTestSetup();
189
+
190
+ const runtime = createRuntime({
191
+ stackInstance,
192
+ context,
193
+ driver,
194
+ verify: { mode: 'onFirstUse', requireMarker: false },
195
+ });
196
+
197
+ const ops = runtime.operations();
198
+ expect(ops).toBeDefined();
199
+ expect(ops.byType).toBeDefined();
200
+ });
201
+
202
+ it('returns null telemetry when no events', () => {
203
+ const { stackInstance, context, driver } = createTestSetup();
204
+
205
+ const runtime = createRuntime({
206
+ stackInstance,
207
+ context,
208
+ driver,
209
+ verify: { mode: 'onFirstUse', requireMarker: false },
210
+ });
211
+
212
+ expect(runtime.telemetry()).toBeNull();
213
+ });
214
+
215
+ it('closes runtime and driver', async () => {
216
+ const { stackInstance, context, driver } = createTestSetup();
217
+
218
+ const runtime = createRuntime({
219
+ stackInstance,
220
+ context,
221
+ driver,
222
+ verify: { mode: 'onFirstUse', requireMarker: false },
223
+ });
224
+
225
+ await runtime.close();
226
+ expect(driver.close).toHaveBeenCalled();
227
+ });
228
+
229
+ it('validates codec registry at startup when verify mode is startup', () => {
230
+ const { stackInstance, context, driver } = createTestSetup();
231
+
232
+ const runtime = createRuntime({
233
+ stackInstance,
234
+ context,
235
+ driver,
236
+ verify: { mode: 'startup', requireMarker: false },
237
+ });
238
+
239
+ expect(runtime).toBeDefined();
240
+ });
241
+ });
package/test/utils.ts ADDED
@@ -0,0 +1,292 @@
1
+ import type { ExecutionPlan, ResultType } from '@prisma-next/contract/types';
2
+ import { coreHash, profileHash } from '@prisma-next/contract/types';
3
+ import { instantiateExecutionStack } from '@prisma-next/core-execution-plane/stack';
4
+ import type { RuntimeDriverDescriptor } from '@prisma-next/core-execution-plane/types';
5
+ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
6
+ import type { Adapter, LoweredStatement, SelectAst } from '@prisma-next/sql-relational-core/ast';
7
+ import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
8
+ import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
9
+ import { collectAsync, drainAsyncIterable } from '@prisma-next/test-utils';
10
+ import type { Client } from 'pg';
11
+ import type { SqlStatement } from '../src/exports';
12
+ import {
13
+ createExecutionContext,
14
+ type createRuntime,
15
+ createSqlExecutionStack,
16
+ ensureSchemaStatement,
17
+ ensureTableStatement,
18
+ writeContractMarker,
19
+ } from '../src/exports';
20
+ import type {
21
+ ExecutionContext,
22
+ SqlRuntimeAdapterDescriptor,
23
+ SqlRuntimeAdapterInstance,
24
+ SqlRuntimeDriverInstance,
25
+ SqlRuntimeExtensionDescriptor,
26
+ SqlRuntimeTargetDescriptor,
27
+ } from '../src/sql-context';
28
+
29
+ /**
30
+ * Executes a plan and collects all results into an array.
31
+ * This helper DRYs up the common pattern of executing plans in tests.
32
+ * The return type is inferred from the plan's type parameter.
33
+ */
34
+ export async function executePlanAndCollect<
35
+ P extends ExecutionPlan<ResultType<P>> | SqlQueryPlan<ResultType<P>>,
36
+ >(runtime: ReturnType<typeof createRuntime>, plan: P): Promise<ResultType<P>[]> {
37
+ type Row = ResultType<P>;
38
+ return collectAsync<Row>(runtime.execute<Row>(plan));
39
+ }
40
+
41
+ /**
42
+ * Drains a plan execution, consuming all results without collecting them.
43
+ * Useful for testing side effects without memory overhead.
44
+ */
45
+ export async function drainPlanExecution(
46
+ runtime: ReturnType<typeof createRuntime>,
47
+ plan: ExecutionPlan | SqlQueryPlan<unknown>,
48
+ ): Promise<void> {
49
+ return drainAsyncIterable(runtime.execute(plan));
50
+ }
51
+
52
+ /**
53
+ * Executes a SQL statement on a database client.
54
+ */
55
+ export async function executeStatement(client: Client, statement: SqlStatement): Promise<void> {
56
+ if (statement.params.length > 0) {
57
+ await client.query(statement.sql, [...statement.params]);
58
+ return;
59
+ }
60
+
61
+ await client.query(statement.sql);
62
+ }
63
+
64
+ /**
65
+ * Sets up database schema and data, then writes the contract marker.
66
+ * This helper DRYs up the common pattern of database setup in tests.
67
+ */
68
+ export async function setupTestDatabase(
69
+ client: Client,
70
+ contract: SqlContract<SqlStorage>,
71
+ setupFn: (client: Client) => Promise<void>,
72
+ ): Promise<void> {
73
+ await client.query('drop schema if exists prisma_contract cascade');
74
+ await client.query('create schema if not exists public');
75
+
76
+ await setupFn(client);
77
+
78
+ await executeStatement(client, ensureSchemaStatement);
79
+ await executeStatement(client, ensureTableStatement);
80
+ const write = writeContractMarker({
81
+ storageHash: contract.storageHash,
82
+ profileHash: contract.profileHash ?? contract.storageHash,
83
+ contractJson: contract,
84
+ canonicalVersion: 1,
85
+ });
86
+ await executeStatement(client, write.insert);
87
+ }
88
+
89
+ /**
90
+ * Writes a contract marker to the database.
91
+ * This helper DRYs up the common pattern of writing contract markers in tests.
92
+ */
93
+ export async function writeTestContractMarker(
94
+ client: Client,
95
+ contract: SqlContract<SqlStorage>,
96
+ ): Promise<void> {
97
+ const write = writeContractMarker({
98
+ storageHash: contract.storageHash,
99
+ profileHash: contract.profileHash ?? contract.storageHash,
100
+ contractJson: contract,
101
+ canonicalVersion: 1,
102
+ });
103
+ await executeStatement(client, write.insert);
104
+ }
105
+
106
+ /**
107
+ * Creates a test adapter descriptor from a raw adapter.
108
+ * Wraps the adapter in an SqlRuntimeAdapterDescriptor with static contributions
109
+ * derived from the adapter's codec registry.
110
+ */
111
+ export function createTestAdapterDescriptor(
112
+ adapter: Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
113
+ ): SqlRuntimeAdapterDescriptor<'postgres'> {
114
+ const codecRegistry = adapter.profile.codecs();
115
+ return {
116
+ kind: 'adapter' as const,
117
+ id: 'test-adapter',
118
+ version: '0.0.1',
119
+ familyId: 'sql' as const,
120
+ targetId: 'postgres' as const,
121
+ codecs: () => codecRegistry,
122
+ operationSignatures: () => [],
123
+ parameterizedCodecs: () => [],
124
+ create(): SqlRuntimeAdapterInstance<'postgres'> {
125
+ return Object.assign({ familyId: 'sql' as const, targetId: 'postgres' as const }, adapter);
126
+ },
127
+ };
128
+ }
129
+
130
+ /**
131
+ * Creates a test target descriptor with empty static contributions.
132
+ */
133
+ export function createTestTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {
134
+ return {
135
+ kind: 'target' as const,
136
+ id: 'postgres',
137
+ version: '0.0.1',
138
+ familyId: 'sql' as const,
139
+ targetId: 'postgres' as const,
140
+ codecs: () => createCodecRegistry(),
141
+ operationSignatures: () => [],
142
+ parameterizedCodecs: () => [],
143
+ create() {
144
+ return { familyId: 'sql' as const, targetId: 'postgres' as const };
145
+ },
146
+ };
147
+ }
148
+
149
+ /**
150
+ * Creates an ExecutionContext for testing.
151
+ * This helper DRYs up the common pattern of context creation in tests.
152
+ *
153
+ * Accepts a raw adapter and optional extension descriptors, wrapping the
154
+ * adapter in a descriptor internally for descriptor-first context creation.
155
+ */
156
+ export function createTestContext<TContract extends SqlContract<SqlStorage>>(
157
+ contract: TContract,
158
+ adapter: Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
159
+ options?: {
160
+ extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;
161
+ },
162
+ ): ExecutionContext<TContract> {
163
+ return createExecutionContext({
164
+ contract,
165
+ stack: {
166
+ target: createTestTargetDescriptor(),
167
+ adapter: createTestAdapterDescriptor(adapter),
168
+ extensionPacks: options?.extensionPacks ?? [],
169
+ },
170
+ });
171
+ }
172
+
173
+ export function createTestStackInstance(options?: {
174
+ extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;
175
+ driver?: RuntimeDriverDescriptor<
176
+ 'sql',
177
+ 'postgres',
178
+ unknown,
179
+ SqlRuntimeDriverInstance<'postgres'>
180
+ >;
181
+ }) {
182
+ const stack = createSqlExecutionStack({
183
+ target: createTestTargetDescriptor(),
184
+ adapter: createTestAdapterDescriptor(createStubAdapter()),
185
+ driver: options?.driver,
186
+ extensionPacks: options?.extensionPacks ?? [],
187
+ });
188
+
189
+ return instantiateExecutionStack(stack);
190
+ }
191
+
192
+ /**
193
+ * Creates a stub adapter for testing.
194
+ * This helper DRYs up the common pattern of adapter creation in tests.
195
+ *
196
+ * The stub adapter includes simple codecs for common test types (pg/int4@1, pg/text@1, pg/timestamptz@1)
197
+ * to enable type inference in tests without requiring the postgres adapter package.
198
+ */
199
+ export function createStubAdapter(): Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement> {
200
+ const codecRegistry = createCodecRegistry();
201
+
202
+ // Register stub codecs for common test types
203
+ // These match the codec IDs used in test contracts (pg/int4@1, pg/text@1, pg/timestamptz@1)
204
+ // but don't require importing from the postgres adapter package
205
+ codecRegistry.register(
206
+ codec({
207
+ typeId: 'pg/int4@1',
208
+ targetTypes: ['int4'],
209
+ encode: (value: number) => value,
210
+ decode: (wire: number) => wire,
211
+ }),
212
+ );
213
+
214
+ codecRegistry.register(
215
+ codec({
216
+ typeId: 'pg/text@1',
217
+ targetTypes: ['text'],
218
+ encode: (value: string) => value,
219
+ decode: (wire: string) => wire,
220
+ }),
221
+ );
222
+
223
+ codecRegistry.register(
224
+ codec({
225
+ typeId: 'pg/timestamptz@1',
226
+ targetTypes: ['timestamptz'],
227
+ encode: (value: string | Date) => (value instanceof Date ? value.toISOString() : value),
228
+ decode: (wire: string | Date) =>
229
+ typeof wire === 'string' ? wire : wire instanceof Date ? wire.toISOString() : String(wire),
230
+ }),
231
+ );
232
+
233
+ return {
234
+ profile: {
235
+ id: 'stub-profile',
236
+ target: 'postgres',
237
+ capabilities: {},
238
+ codecs() {
239
+ return codecRegistry;
240
+ },
241
+ },
242
+ lower(ast: SelectAst, ctx: { contract: SqlContract<SqlStorage>; params?: readonly unknown[] }) {
243
+ const sqlText = JSON.stringify(ast);
244
+ return {
245
+ profileId: this.profile.id,
246
+ body: Object.freeze({ sql: sqlText, params: ctx.params ? [...ctx.params] : [] }),
247
+ };
248
+ },
249
+ };
250
+ }
251
+
252
+ /**
253
+ * Creates a valid test contract without using validateContract.
254
+ * Ensures all required fields are present (mappings, capabilities, extensionPacks, meta, sources)
255
+ * and returns the contract with proper typing.
256
+ * This helper allows tests to create contracts without depending on sql-query.
257
+ */
258
+ export function createTestContract(
259
+ contract: Partial<Omit<SqlContract<SqlStorage>, 'storageHash' | 'profileHash'>> & {
260
+ storageHash?: string;
261
+ profileHash?: string;
262
+ },
263
+ ): SqlContract<SqlStorage> {
264
+ const { execution, ...rest } = contract;
265
+
266
+ return {
267
+ ...rest,
268
+ schemaVersion: rest.schemaVersion ?? '1',
269
+ target: rest.target ?? 'postgres',
270
+ targetFamily: rest.targetFamily ?? 'sql',
271
+ storage: rest.storage ?? { tables: {} },
272
+ models: rest.models ?? {},
273
+ relations: rest.relations ?? {},
274
+ mappings: rest.mappings ?? { codecTypes: {}, operationTypes: {} },
275
+ capabilities: rest.capabilities ?? {},
276
+ extensionPacks: rest.extensionPacks ?? {},
277
+ meta: rest.meta ?? {},
278
+ sources: rest.sources ?? {},
279
+ ...(execution ? { execution } : {}),
280
+ storageHash: coreHash(rest.storageHash ?? 'sha256:testcore'),
281
+ profileHash: profileHash(rest.profileHash ?? 'sha256:testprofile'),
282
+ } satisfies SqlContract<SqlStorage>;
283
+ }
284
+
285
+ // Re-export generic utilities from test-utils
286
+ export {
287
+ collectAsync,
288
+ createDevDatabase,
289
+ type DevDatabase,
290
+ teardownTestDatabase,
291
+ withClient,
292
+ } from '@prisma-next/test-utils';