@prisma-next/sql-runtime 0.3.0-dev.34 → 0.3.0-dev.36

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 (163) hide show
  1. package/README.md +115 -24
  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 +26 -20
  13. package/src/codecs/decoding.ts +84 -3
  14. package/src/codecs/encoding.ts +15 -2
  15. package/src/codecs/json-schema-validation.ts +61 -0
  16. package/src/exports/index.ts +9 -4
  17. package/src/lower-sql-plan.ts +8 -8
  18. package/src/sql-context.ts +286 -245
  19. package/src/sql-family-adapter.ts +9 -5
  20. package/src/sql-marker.ts +2 -2
  21. package/src/sql-runtime.ts +89 -23
  22. package/test/async-iterable-result.test.ts +42 -34
  23. package/test/context.types.test-d.ts +12 -14
  24. package/test/execution-stack.test.ts +166 -0
  25. package/test/json-schema-validation.test.ts +653 -0
  26. package/test/parameterized-types.test.ts +182 -196
  27. package/test/sql-context.test.ts +292 -117
  28. package/test/sql-family-adapter.test.ts +7 -6
  29. package/test/sql-runtime.test.ts +117 -31
  30. package/test/utils.ts +76 -50
  31. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
  32. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
  33. package/dist/amcheck-24VY6X5V.js +0 -13
  34. package/dist/amcheck-24VY6X5V.js.map +0 -1
  35. package/dist/bloom-VS74NLHT.js +0 -13
  36. package/dist/bloom-VS74NLHT.js.map +0 -1
  37. package/dist/btree_gin-WBC4EAAI.js +0 -13
  38. package/dist/btree_gin-WBC4EAAI.js.map +0 -1
  39. package/dist/btree_gist-UNC6QD3M.js +0 -13
  40. package/dist/btree_gist-UNC6QD3M.js.map +0 -1
  41. package/dist/chunk-3KTOEDFX.js +0 -49
  42. package/dist/chunk-3KTOEDFX.js.map +0 -1
  43. package/dist/chunk-47DZBRQC.js +0 -1280
  44. package/dist/chunk-47DZBRQC.js.map +0 -1
  45. package/dist/chunk-52N6AFZM.js +0 -133
  46. package/dist/chunk-52N6AFZM.js.map +0 -1
  47. package/dist/chunk-7D4SUZUM.js +0 -38
  48. package/dist/chunk-7D4SUZUM.js.map +0 -1
  49. package/dist/chunk-APA6GHYY.js +0 -537
  50. package/dist/chunk-APA6GHYY.js.map +0 -1
  51. package/dist/chunk-ECWIHLAT.js +0 -37
  52. package/dist/chunk-ECWIHLAT.js.map +0 -1
  53. package/dist/chunk-EI626SDC.js +0 -105
  54. package/dist/chunk-EI626SDC.js.map +0 -1
  55. package/dist/chunk-UKKOYUGL.js +0 -578
  56. package/dist/chunk-UKKOYUGL.js.map +0 -1
  57. package/dist/chunk-XPLNMXQV.js +0 -1537
  58. package/dist/chunk-XPLNMXQV.js.map +0 -1
  59. package/dist/citext-T7MXGUY7.js +0 -13
  60. package/dist/citext-T7MXGUY7.js.map +0 -1
  61. package/dist/client-5FENX6AW.js +0 -299
  62. package/dist/client-5FENX6AW.js.map +0 -1
  63. package/dist/cube-TFDQBZCI.js +0 -13
  64. package/dist/cube-TFDQBZCI.js.map +0 -1
  65. package/dist/dict_int-AEUOPGWP.js +0 -13
  66. package/dist/dict_int-AEUOPGWP.js.map +0 -1
  67. package/dist/dict_xsyn-DAAYX3FL.js +0 -13
  68. package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
  69. package/dist/dist-AQ3LWXOX.js +0 -570
  70. package/dist/dist-AQ3LWXOX.js.map +0 -1
  71. package/dist/dist-LBVX6BJW.js +0 -189
  72. package/dist/dist-LBVX6BJW.js.map +0 -1
  73. package/dist/dist-WLKUVDN2.js +0 -5127
  74. package/dist/dist-WLKUVDN2.js.map +0 -1
  75. package/dist/earthdistance-KIGTF4LE.js +0 -13
  76. package/dist/earthdistance-KIGTF4LE.js.map +0 -1
  77. package/dist/file_fdw-5N55UP6I.js +0 -13
  78. package/dist/file_fdw-5N55UP6I.js.map +0 -1
  79. package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
  80. package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
  81. package/dist/hstore-YX726NKN.js +0 -13
  82. package/dist/hstore-YX726NKN.js.map +0 -1
  83. package/dist/http-exception-FZY2H4OF.js +0 -8
  84. package/dist/http-exception-FZY2H4OF.js.map +0 -1
  85. package/dist/index.js +0 -30
  86. package/dist/index.js.map +0 -1
  87. package/dist/intarray-NKVXNO2D.js +0 -13
  88. package/dist/intarray-NKVXNO2D.js.map +0 -1
  89. package/dist/isn-FTEMJGEV.js +0 -13
  90. package/dist/isn-FTEMJGEV.js.map +0 -1
  91. package/dist/lo-DB7L4NGI.js +0 -13
  92. package/dist/lo-DB7L4NGI.js.map +0 -1
  93. package/dist/logger-WQ7SHNDD.js +0 -68
  94. package/dist/logger-WQ7SHNDD.js.map +0 -1
  95. package/dist/ltree-Z32TZT6W.js +0 -13
  96. package/dist/ltree-Z32TZT6W.js.map +0 -1
  97. package/dist/nodefs-NM46ACH7.js +0 -31
  98. package/dist/nodefs-NM46ACH7.js.map +0 -1
  99. package/dist/opfs-ahp-NJO33LVZ.js +0 -332
  100. package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
  101. package/dist/pageinspect-YP3IZR4X.js +0 -13
  102. package/dist/pageinspect-YP3IZR4X.js.map +0 -1
  103. package/dist/pg_buffercache-7TD5J2FB.js +0 -13
  104. package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
  105. package/dist/pg_dump-SG4KYBUB.js +0 -2492
  106. package/dist/pg_dump-SG4KYBUB.js.map +0 -1
  107. package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
  108. package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
  109. package/dist/pg_surgery-J2MUEWEP.js +0 -13
  110. package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
  111. package/dist/pg_trgm-7VNQOYS6.js +0 -13
  112. package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
  113. package/dist/pg_visibility-TTSIPHFL.js +0 -13
  114. package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
  115. package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
  116. package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
  117. package/dist/proxy-signals-GUDAMDHV.js +0 -39
  118. package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
  119. package/dist/seg-IYVDLE4O.js +0 -13
  120. package/dist/seg-IYVDLE4O.js.map +0 -1
  121. package/dist/src/codecs/decoding.d.ts +0 -4
  122. package/dist/src/codecs/decoding.d.ts.map +0 -1
  123. package/dist/src/codecs/encoding.d.ts +0 -5
  124. package/dist/src/codecs/encoding.d.ts.map +0 -1
  125. package/dist/src/codecs/validation.d.ts +0 -6
  126. package/dist/src/codecs/validation.d.ts.map +0 -1
  127. package/dist/src/exports/index.d.ts +0 -11
  128. package/dist/src/exports/index.d.ts.map +0 -1
  129. package/dist/src/index.d.ts +0 -2
  130. package/dist/src/index.d.ts.map +0 -1
  131. package/dist/src/lower-sql-plan.d.ts +0 -15
  132. package/dist/src/lower-sql-plan.d.ts.map +0 -1
  133. package/dist/src/sql-context.d.ts +0 -130
  134. package/dist/src/sql-context.d.ts.map +0 -1
  135. package/dist/src/sql-family-adapter.d.ts +0 -10
  136. package/dist/src/sql-family-adapter.d.ts.map +0 -1
  137. package/dist/src/sql-marker.d.ts +0 -22
  138. package/dist/src/sql-marker.d.ts.map +0 -1
  139. package/dist/src/sql-runtime.d.ts +0 -25
  140. package/dist/src/sql-runtime.d.ts.map +0 -1
  141. package/dist/tablefunc-EF4RCS7S.js +0 -13
  142. package/dist/tablefunc-EF4RCS7S.js.map +0 -1
  143. package/dist/tcn-3VT5BQYW.js +0 -13
  144. package/dist/tcn-3VT5BQYW.js.map +0 -1
  145. package/dist/test/utils.d.ts +0 -60
  146. package/dist/test/utils.d.ts.map +0 -1
  147. package/dist/test/utils.js +0 -24635
  148. package/dist/test/utils.js.map +0 -1
  149. package/dist/tiny-CW6F4GX6.js +0 -10
  150. package/dist/tiny-CW6F4GX6.js.map +0 -1
  151. package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
  152. package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
  153. package/dist/tsm_system_time-76WEIMBG.js +0 -13
  154. package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
  155. package/dist/unaccent-7RYF3R64.js +0 -13
  156. package/dist/unaccent-7RYF3R64.js.map +0 -1
  157. package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
  158. package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
  159. package/dist/uuid_ossp-4ETE4FPE.js +0 -13
  160. package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
  161. package/dist/vector-74GPNV7V.js +0 -13
  162. package/dist/vector-74GPNV7V.js.map +0 -1
  163. package/src/index.ts +0 -1
@@ -1,21 +1,21 @@
1
+ import { coreHash } from '@prisma-next/contract/types';
1
2
  import type { SqlContract, SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
2
- import type { SelectAst } from '@prisma-next/sql-relational-core/ast';
3
3
  import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
4
+ import { ifDefined } from '@prisma-next/utils/defined';
4
5
  import type { Type } from 'arktype';
5
6
  import { type as arktype } from 'arktype';
6
7
  import { describe, expect, it } from 'vitest';
7
- import {
8
- createRuntimeContext,
9
- type RuntimeParameterizedCodecDescriptor,
10
- type SqlRuntimeExtensionDescriptor,
11
- type SqlRuntimeExtensionInstance,
8
+ import type {
9
+ RuntimeParameterizedCodecDescriptor,
10
+ SqlRuntimeExtensionDescriptor,
12
11
  } from '../src/sql-context';
12
+ import { createStubAdapter, createTestContext } from './utils';
13
13
 
14
14
  // =============================================================================
15
15
  // Test helpers
16
16
  // =============================================================================
17
17
 
18
- function createTestContract(
18
+ function createParamTypesTestContract(
19
19
  options?: Partial<{
20
20
  types: Record<string, StorageTypeInstance>;
21
21
  tableColumns: Record<
@@ -34,7 +34,7 @@ function createTestContract(
34
34
  schemaVersion: '1',
35
35
  targetFamily: 'sql',
36
36
  target: 'postgres',
37
- coreHash: 'sha256:test',
37
+ storageHash: coreHash('sha256:test'),
38
38
  models: {},
39
39
  relations: {},
40
40
  storage: {
@@ -49,7 +49,7 @@ function createTestContract(
49
49
  foreignKeys: [],
50
50
  },
51
51
  },
52
- ...(options?.types ? { types: options.types } : {}),
52
+ ...ifDefined('types', options?.types),
53
53
  },
54
54
  extensionPacks: {},
55
55
  capabilities: {},
@@ -62,59 +62,6 @@ function createTestContract(
62
62
  };
63
63
  }
64
64
 
65
- function createTestAdapterDescriptor() {
66
- const codecs = createCodecRegistry();
67
- codecs.register(
68
- codec({
69
- typeId: 'pg/int4@1',
70
- targetTypes: ['int4'],
71
- encode: (v: number) => v,
72
- decode: (w: number) => w,
73
- }),
74
- );
75
-
76
- return {
77
- kind: 'adapter' as const,
78
- id: 'test-adapter',
79
- version: '0.0.1',
80
- familyId: 'sql' as const,
81
- targetId: 'postgres' as const,
82
- create() {
83
- return {
84
- familyId: 'sql' as const,
85
- targetId: 'postgres' as const,
86
- profile: {
87
- id: 'test-profile',
88
- target: 'postgres',
89
- capabilities: {},
90
- codecs() {
91
- return codecs;
92
- },
93
- },
94
- lower(ast: SelectAst) {
95
- return {
96
- profileId: 'test-profile',
97
- body: Object.freeze({ sql: JSON.stringify(ast), params: [] }),
98
- };
99
- },
100
- };
101
- },
102
- };
103
- }
104
-
105
- function createTestTargetDescriptor() {
106
- return {
107
- kind: 'target' as const,
108
- id: 'postgres',
109
- version: '0.0.1',
110
- familyId: 'sql' as const,
111
- targetId: 'postgres' as const,
112
- create() {
113
- return { familyId: 'sql' as const, targetId: 'postgres' as const };
114
- },
115
- };
116
- }
117
-
118
65
  // =============================================================================
119
66
  // Tests: Parameterized type validation
120
67
  // =============================================================================
@@ -122,19 +69,15 @@ function createTestTargetDescriptor() {
122
69
  describe('parameterized types', () => {
123
70
  describe('storage.types validation', () => {
124
71
  it('creates context with empty storage.types', () => {
125
- const contract = createTestContract({ types: {} });
126
- const context = createRuntimeContext({
127
- contract,
128
- target: createTestTargetDescriptor(),
129
- adapter: createTestAdapterDescriptor(),
130
- });
72
+ const contract = createParamTypesTestContract({ types: {} });
73
+ const context = createTestContext(contract, createStubAdapter());
131
74
 
132
75
  expect(context.contract.storage.types).toEqual({});
133
76
  expect(context.types).toEqual({});
134
77
  });
135
78
 
136
79
  it('creates context with storage.types containing valid type instances', () => {
137
- const contract = createTestContract({
80
+ const contract = createParamTypesTestContract({
138
81
  types: {
139
82
  Vector1536: {
140
83
  codecId: 'pg/vector@1',
@@ -143,11 +86,7 @@ describe('parameterized types', () => {
143
86
  },
144
87
  },
145
88
  });
146
- const context = createRuntimeContext({
147
- contract,
148
- target: createTestTargetDescriptor(),
149
- adapter: createTestAdapterDescriptor(),
150
- });
89
+ const context = createTestContext(contract, createStubAdapter());
151
90
 
152
91
  expect(context.contract.storage.types).toEqual({
153
92
  Vector1536: {
@@ -157,7 +96,7 @@ describe('parameterized types', () => {
157
96
  },
158
97
  });
159
98
  // types registry should contain the raw type instance (no init hook provided)
160
- expect(context.types?.['Vector1536']).toBeDefined();
99
+ expect(context.types['Vector1536']).toBeDefined();
161
100
  });
162
101
  });
163
102
 
@@ -175,38 +114,40 @@ describe('parameterized types', () => {
175
114
  {
176
115
  codecId: 'pg/vector@1',
177
116
  paramsSchema: options?.paramsSchema ?? vectorParamsSchema,
178
- ...(options?.init ? { init: options.init } : {}),
117
+ ...ifDefined('init', options?.init),
179
118
  },
180
119
  ];
181
120
 
121
+ const registry = createCodecRegistry();
122
+ registry.register(
123
+ codec({
124
+ typeId: 'pg/vector@1',
125
+ targetTypes: ['vector'],
126
+ encode: (v: number[]) => v,
127
+ decode: (w: number[]) => w,
128
+ }),
129
+ );
130
+
182
131
  return {
183
132
  kind: 'extension' as const,
184
133
  id: 'pgvector',
185
134
  version: '0.0.1',
186
135
  familyId: 'sql' as const,
187
136
  targetId: 'postgres' as const,
188
- create(): SqlRuntimeExtensionInstance<'postgres'> {
189
- const registry = createCodecRegistry();
190
- registry.register(
191
- codec({
192
- typeId: 'pg/vector@1',
193
- targetTypes: ['vector'],
194
- encode: (v: number[]) => v,
195
- decode: (w: number[]) => w,
196
- }),
197
- );
137
+ codecs: () => registry,
138
+ operationSignatures: () => [],
139
+ parameterizedCodecs: () => parameterizedCodecs,
140
+ create() {
198
141
  return {
199
142
  familyId: 'sql' as const,
200
143
  targetId: 'postgres' as const,
201
- codecs: () => registry,
202
- parameterizedCodecs: () => parameterizedCodecs,
203
144
  };
204
145
  },
205
146
  };
206
147
  }
207
148
 
208
149
  it('validates typeParams against codec paramsSchema', () => {
209
- const contract = createTestContract({
150
+ const contract = createParamTypesTestContract({
210
151
  types: {
211
152
  Vector1536: {
212
153
  codecId: 'pg/vector@1',
@@ -216,18 +157,15 @@ describe('parameterized types', () => {
216
157
  },
217
158
  });
218
159
 
219
- const context = createRuntimeContext({
220
- contract,
221
- target: createTestTargetDescriptor(),
222
- adapter: createTestAdapterDescriptor(),
160
+ const context = createTestContext(contract, createStubAdapter(), {
223
161
  extensionPacks: [createVectorExtensionDescriptor()],
224
162
  });
225
163
 
226
- expect(context.types?.['Vector1536']).toBeDefined();
164
+ expect(context.types['Vector1536']).toBeDefined();
227
165
  });
228
166
 
229
167
  it('rejects invalid typeParams with stable error code', () => {
230
- const contract = createTestContract({
168
+ const contract = createParamTypesTestContract({
231
169
  types: {
232
170
  InvalidVector: {
233
171
  codecId: 'pg/vector@1',
@@ -239,10 +177,7 @@ describe('parameterized types', () => {
239
177
 
240
178
  let thrownError: unknown;
241
179
  try {
242
- createRuntimeContext({
243
- contract,
244
- target: createTestTargetDescriptor(),
245
- adapter: createTestAdapterDescriptor(),
180
+ createTestContext(contract, createStubAdapter(), {
246
181
  extensionPacks: [createVectorExtensionDescriptor()],
247
182
  });
248
183
  } catch (e) {
@@ -262,7 +197,7 @@ describe('parameterized types', () => {
262
197
  });
263
198
 
264
199
  it('rejects missing required typeParams with stable error code', () => {
265
- const contract = createTestContract({
200
+ const contract = createParamTypesTestContract({
266
201
  types: {
267
202
  InvalidVector: {
268
203
  codecId: 'pg/vector@1',
@@ -274,10 +209,7 @@ describe('parameterized types', () => {
274
209
 
275
210
  let thrownError: unknown;
276
211
  try {
277
- createRuntimeContext({
278
- contract,
279
- target: createTestTargetDescriptor(),
280
- adapter: createTestAdapterDescriptor(),
212
+ createTestContext(contract, createStubAdapter(), {
281
213
  extensionPacks: [createVectorExtensionDescriptor()],
282
214
  });
283
215
  } catch (e) {
@@ -304,38 +236,42 @@ describe('parameterized types', () => {
304
236
  isVector: true,
305
237
  });
306
238
 
239
+ const registry = createCodecRegistry();
240
+ registry.register(
241
+ codec({
242
+ typeId: 'pg/vector@1',
243
+ targetTypes: ['vector'],
244
+ encode: (v: number[]) => v,
245
+ decode: (w: number[]) => w,
246
+ }),
247
+ );
248
+
249
+ const parameterizedCodecs = [
250
+ {
251
+ codecId: 'pg/vector@1',
252
+ paramsSchema: vectorParamsSchema,
253
+ init: initFn,
254
+ },
255
+ ];
256
+
307
257
  const extensionDescriptor: SqlRuntimeExtensionDescriptor<'postgres'> = {
308
258
  kind: 'extension' as const,
309
259
  id: 'pgvector',
310
260
  version: '0.0.1',
311
261
  familyId: 'sql' as const,
312
262
  targetId: 'postgres' as const,
313
- create(): SqlRuntimeExtensionInstance<'postgres'> {
314
- const registry = createCodecRegistry();
315
- registry.register(
316
- codec({
317
- typeId: 'pg/vector@1',
318
- targetTypes: ['vector'],
319
- encode: (v: number[]) => v,
320
- decode: (w: number[]) => w,
321
- }),
322
- );
263
+ codecs: () => registry,
264
+ operationSignatures: () => [],
265
+ parameterizedCodecs: () => parameterizedCodecs,
266
+ create() {
323
267
  return {
324
268
  familyId: 'sql' as const,
325
269
  targetId: 'postgres' as const,
326
- codecs: () => registry,
327
- parameterizedCodecs: () => [
328
- {
329
- codecId: 'pg/vector@1',
330
- paramsSchema: vectorParamsSchema,
331
- init: initFn,
332
- },
333
- ],
334
270
  };
335
271
  },
336
272
  };
337
273
 
338
- const contract = createTestContract({
274
+ const contract = createParamTypesTestContract({
339
275
  types: {
340
276
  Vector1536: {
341
277
  codecId: 'pg/vector@1',
@@ -345,14 +281,11 @@ describe('parameterized types', () => {
345
281
  },
346
282
  });
347
283
 
348
- const context = createRuntimeContext({
349
- contract,
350
- target: createTestTargetDescriptor(),
351
- adapter: createTestAdapterDescriptor(),
284
+ const context = createTestContext(contract, createStubAdapter(), {
352
285
  extensionPacks: [extensionDescriptor],
353
286
  });
354
287
 
355
- expect(context.types?.['Vector1536']).toEqual({
288
+ expect(context.types['Vector1536']).toEqual({
356
289
  dimensions: 1536,
357
290
  isVector: true,
358
291
  });
@@ -363,38 +296,41 @@ describe('parameterized types', () => {
363
296
  length: 'number',
364
297
  });
365
298
 
299
+ const registry = createCodecRegistry();
300
+ registry.register(
301
+ codec({
302
+ typeId: 'pg/vector@1',
303
+ targetTypes: ['vector'],
304
+ encode: (v: number[]) => v,
305
+ decode: (w: number[]) => w,
306
+ }),
307
+ );
308
+
309
+ const parameterizedCodecs = [
310
+ {
311
+ codecId: 'pg/vector@1',
312
+ paramsSchema: vectorParamsSchema,
313
+ },
314
+ ];
315
+
366
316
  const extensionDescriptor: SqlRuntimeExtensionDescriptor<'postgres'> = {
367
317
  kind: 'extension' as const,
368
318
  id: 'pgvector',
369
319
  version: '0.0.1',
370
320
  familyId: 'sql' as const,
371
321
  targetId: 'postgres' as const,
372
- create(): SqlRuntimeExtensionInstance<'postgres'> {
373
- const registry = createCodecRegistry();
374
- registry.register(
375
- codec({
376
- typeId: 'pg/vector@1',
377
- targetTypes: ['vector'],
378
- encode: (v: number[]) => v,
379
- decode: (w: number[]) => w,
380
- }),
381
- );
322
+ codecs: () => registry,
323
+ operationSignatures: () => [],
324
+ parameterizedCodecs: () => parameterizedCodecs,
325
+ create() {
382
326
  return {
383
327
  familyId: 'sql' as const,
384
328
  targetId: 'postgres' as const,
385
- codecs: () => registry,
386
- parameterizedCodecs: () => [
387
- {
388
- codecId: 'pg/vector@1',
389
- paramsSchema: vectorParamsSchema,
390
- // No init hook
391
- },
392
- ],
393
329
  };
394
330
  },
395
331
  };
396
332
 
397
- const contract = createTestContract({
333
+ const contract = createParamTypesTestContract({
398
334
  types: {
399
335
  Vector1536: {
400
336
  codecId: 'pg/vector@1',
@@ -404,15 +340,12 @@ describe('parameterized types', () => {
404
340
  },
405
341
  });
406
342
 
407
- const context = createRuntimeContext({
408
- contract,
409
- target: createTestTargetDescriptor(),
410
- adapter: createTestAdapterDescriptor(),
343
+ const context = createTestContext(contract, createStubAdapter(), {
411
344
  extensionPacks: [extensionDescriptor],
412
345
  });
413
346
 
414
347
  // Without init hook, stores the full type instance (matches contract typing)
415
- expect(context.types?.['Vector1536']).toEqual({
348
+ expect(context.types['Vector1536']).toEqual({
416
349
  codecId: 'pg/vector@1',
417
350
  nativeType: 'vector',
418
351
  typeParams: { length: 1536 },
@@ -426,37 +359,41 @@ describe('parameterized types', () => {
426
359
  length: 'number',
427
360
  });
428
361
 
362
+ const registry = createCodecRegistry();
363
+ registry.register(
364
+ codec({
365
+ typeId: 'pg/vector@1',
366
+ targetTypes: ['vector'],
367
+ encode: (v: number[]) => v,
368
+ decode: (w: number[]) => w,
369
+ }),
370
+ );
371
+
372
+ const parameterizedCodecs = [
373
+ {
374
+ codecId: 'pg/vector@1',
375
+ paramsSchema: vectorParamsSchema,
376
+ },
377
+ ];
378
+
429
379
  const extensionDescriptor: SqlRuntimeExtensionDescriptor<'postgres'> = {
430
380
  kind: 'extension' as const,
431
381
  id: 'pgvector',
432
382
  version: '0.0.1',
433
383
  familyId: 'sql' as const,
434
384
  targetId: 'postgres' as const,
435
- create(): SqlRuntimeExtensionInstance<'postgres'> {
436
- const registry = createCodecRegistry();
437
- registry.register(
438
- codec({
439
- typeId: 'pg/vector@1',
440
- targetTypes: ['vector'],
441
- encode: (v: number[]) => v,
442
- decode: (w: number[]) => w,
443
- }),
444
- );
385
+ codecs: () => registry,
386
+ operationSignatures: () => [],
387
+ parameterizedCodecs: () => parameterizedCodecs,
388
+ create() {
445
389
  return {
446
390
  familyId: 'sql' as const,
447
391
  targetId: 'postgres' as const,
448
- codecs: () => registry,
449
- parameterizedCodecs: () => [
450
- {
451
- codecId: 'pg/vector@1',
452
- paramsSchema: vectorParamsSchema,
453
- },
454
- ],
455
392
  };
456
393
  },
457
394
  };
458
395
 
459
- const contract = createTestContract({
396
+ const contract = createParamTypesTestContract({
460
397
  tableColumns: {
461
398
  id: { nativeType: 'int4', codecId: 'pg/int4@1', nullable: false },
462
399
  embedding: {
@@ -469,10 +406,7 @@ describe('parameterized types', () => {
469
406
  });
470
407
 
471
408
  // Should not throw - valid typeParams
472
- const context = createRuntimeContext({
473
- contract,
474
- target: createTestTargetDescriptor(),
475
- adapter: createTestAdapterDescriptor(),
409
+ const context = createTestContext(contract, createStubAdapter(), {
476
410
  extensionPacks: [extensionDescriptor],
477
411
  });
478
412
 
@@ -484,37 +418,41 @@ describe('parameterized types', () => {
484
418
  length: 'number',
485
419
  });
486
420
 
421
+ const registry = createCodecRegistry();
422
+ registry.register(
423
+ codec({
424
+ typeId: 'pg/vector@1',
425
+ targetTypes: ['vector'],
426
+ encode: (v: number[]) => v,
427
+ decode: (w: number[]) => w,
428
+ }),
429
+ );
430
+
431
+ const parameterizedCodecs = [
432
+ {
433
+ codecId: 'pg/vector@1',
434
+ paramsSchema: vectorParamsSchema,
435
+ },
436
+ ];
437
+
487
438
  const extensionDescriptor: SqlRuntimeExtensionDescriptor<'postgres'> = {
488
439
  kind: 'extension' as const,
489
440
  id: 'pgvector',
490
441
  version: '0.0.1',
491
442
  familyId: 'sql' as const,
492
443
  targetId: 'postgres' as const,
493
- create(): SqlRuntimeExtensionInstance<'postgres'> {
494
- const registry = createCodecRegistry();
495
- registry.register(
496
- codec({
497
- typeId: 'pg/vector@1',
498
- targetTypes: ['vector'],
499
- encode: (v: number[]) => v,
500
- decode: (w: number[]) => w,
501
- }),
502
- );
444
+ codecs: () => registry,
445
+ operationSignatures: () => [],
446
+ parameterizedCodecs: () => parameterizedCodecs,
447
+ create() {
503
448
  return {
504
449
  familyId: 'sql' as const,
505
450
  targetId: 'postgres' as const,
506
- codecs: () => registry,
507
- parameterizedCodecs: () => [
508
- {
509
- codecId: 'pg/vector@1',
510
- paramsSchema: vectorParamsSchema,
511
- },
512
- ],
513
451
  };
514
452
  },
515
453
  };
516
454
 
517
- const contract = createTestContract({
455
+ const contract = createParamTypesTestContract({
518
456
  tableColumns: {
519
457
  id: { nativeType: 'int4', codecId: 'pg/int4@1', nullable: false },
520
458
  embedding: {
@@ -528,10 +466,7 @@ describe('parameterized types', () => {
528
466
 
529
467
  let thrownError: unknown;
530
468
  try {
531
- createRuntimeContext({
532
- contract,
533
- target: createTestTargetDescriptor(),
534
- adapter: createTestAdapterDescriptor(),
469
+ createTestContext(contract, createStubAdapter(), {
535
470
  extensionPacks: [extensionDescriptor],
536
471
  });
537
472
  } catch (e) {
@@ -550,4 +485,55 @@ describe('parameterized types', () => {
550
485
  });
551
486
  });
552
487
  });
488
+
489
+ describe('duplicate codec descriptor detection', () => {
490
+ it('throws RUNTIME.DUPLICATE_PARAMETERIZED_CODEC when multiple extensions provide same codecId', () => {
491
+ const vectorParamsSchema = arktype({
492
+ length: 'number',
493
+ });
494
+
495
+ function createVectorExtension(id: string): SqlRuntimeExtensionDescriptor<'postgres'> {
496
+ const parameterizedCodecs = [
497
+ {
498
+ codecId: 'pg/vector@1',
499
+ paramsSchema: vectorParamsSchema,
500
+ },
501
+ ];
502
+
503
+ return {
504
+ kind: 'extension' as const,
505
+ id,
506
+ version: '0.0.1',
507
+ familyId: 'sql' as const,
508
+ targetId: 'postgres' as const,
509
+ codecs: () => createCodecRegistry(),
510
+ operationSignatures: () => [],
511
+ parameterizedCodecs: () => parameterizedCodecs,
512
+ create() {
513
+ return {
514
+ familyId: 'sql' as const,
515
+ targetId: 'postgres' as const,
516
+ };
517
+ },
518
+ };
519
+ }
520
+
521
+ const contract = createParamTypesTestContract();
522
+
523
+ expect(() =>
524
+ createTestContext(contract, createStubAdapter(), {
525
+ extensionPacks: [createVectorExtension('ext-1'), createVectorExtension('ext-2')],
526
+ }),
527
+ ).toThrow(
528
+ expect.objectContaining({
529
+ code: 'RUNTIME.DUPLICATE_PARAMETERIZED_CODEC',
530
+ category: 'RUNTIME',
531
+ severity: 'error',
532
+ details: {
533
+ codecId: 'pg/vector@1',
534
+ },
535
+ }),
536
+ );
537
+ });
538
+ });
553
539
  });