@prisma-next/sql-runtime 0.3.0-pr.99.6 → 0.3.0

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