@prisma-next/sql-runtime 0.3.0-dev.12 → 0.3.0-dev.123

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 (169) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +141 -24
  3. package/dist/exports-BKjZvwMh.mjs +971 -0
  4. package/dist/exports-BKjZvwMh.mjs.map +1 -0
  5. package/dist/index-eHiENgIB.d.mts +182 -0
  6. package/dist/index-eHiENgIB.d.mts.map +1 -0
  7. package/dist/index.d.mts +2 -0
  8. package/dist/index.mjs +3 -0
  9. package/dist/test/utils.d.mts +82 -0
  10. package/dist/test/utils.d.mts.map +1 -0
  11. package/dist/test/utils.mjs +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/exports/index.ts +19 -7
  18. package/src/lower-sql-plan.ts +8 -8
  19. package/src/plugins/budgets.ts +375 -0
  20. package/src/plugins/lints.ts +211 -0
  21. package/src/sql-context.ts +448 -98
  22. package/src/sql-family-adapter.ts +9 -5
  23. package/src/sql-marker.ts +2 -2
  24. package/src/sql-runtime.ts +126 -30
  25. package/test/async-iterable-result.test.ts +43 -35
  26. package/test/budgets.test.ts +481 -0
  27. package/test/context.types.test-d.ts +68 -0
  28. package/test/execution-stack.test.ts +166 -0
  29. package/test/json-schema-validation.test.ts +575 -0
  30. package/test/lints.test.ts +161 -0
  31. package/test/mutation-default-generators.test.ts +256 -0
  32. package/test/parameterized-types.test.ts +536 -0
  33. package/test/sql-context.test.ts +293 -121
  34. package/test/sql-family-adapter.test.ts +8 -10
  35. package/test/sql-runtime.test.ts +219 -34
  36. package/test/utils.ts +90 -51
  37. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
  38. package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
  39. package/dist/amcheck-24VY6X5V.js +0 -13
  40. package/dist/amcheck-24VY6X5V.js.map +0 -1
  41. package/dist/bloom-VS74NLHT.js +0 -13
  42. package/dist/bloom-VS74NLHT.js.map +0 -1
  43. package/dist/btree_gin-WBC4EAAI.js +0 -13
  44. package/dist/btree_gin-WBC4EAAI.js.map +0 -1
  45. package/dist/btree_gist-UNC6QD3M.js +0 -13
  46. package/dist/btree_gist-UNC6QD3M.js.map +0 -1
  47. package/dist/chunk-3KTOEDFX.js +0 -49
  48. package/dist/chunk-3KTOEDFX.js.map +0 -1
  49. package/dist/chunk-47DZBRQC.js +0 -1280
  50. package/dist/chunk-47DZBRQC.js.map +0 -1
  51. package/dist/chunk-52N6AFZM.js +0 -133
  52. package/dist/chunk-52N6AFZM.js.map +0 -1
  53. package/dist/chunk-7D4SUZUM.js +0 -38
  54. package/dist/chunk-7D4SUZUM.js.map +0 -1
  55. package/dist/chunk-C6I3V3DM.js +0 -455
  56. package/dist/chunk-C6I3V3DM.js.map +0 -1
  57. package/dist/chunk-ECWIHLAT.js +0 -37
  58. package/dist/chunk-ECWIHLAT.js.map +0 -1
  59. package/dist/chunk-EI626SDC.js +0 -105
  60. package/dist/chunk-EI626SDC.js.map +0 -1
  61. package/dist/chunk-UKKOYUGL.js +0 -578
  62. package/dist/chunk-UKKOYUGL.js.map +0 -1
  63. package/dist/chunk-XPLNMXQV.js +0 -1537
  64. package/dist/chunk-XPLNMXQV.js.map +0 -1
  65. package/dist/citext-T7MXGUY7.js +0 -13
  66. package/dist/citext-T7MXGUY7.js.map +0 -1
  67. package/dist/client-5FENX6AW.js +0 -299
  68. package/dist/client-5FENX6AW.js.map +0 -1
  69. package/dist/cube-TFDQBZCI.js +0 -13
  70. package/dist/cube-TFDQBZCI.js.map +0 -1
  71. package/dist/dict_int-AEUOPGWP.js +0 -13
  72. package/dist/dict_int-AEUOPGWP.js.map +0 -1
  73. package/dist/dict_xsyn-DAAYX3FL.js +0 -13
  74. package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
  75. package/dist/dist-AQ3LWXOX.js +0 -570
  76. package/dist/dist-AQ3LWXOX.js.map +0 -1
  77. package/dist/dist-LBVX6BJW.js +0 -189
  78. package/dist/dist-LBVX6BJW.js.map +0 -1
  79. package/dist/dist-WLKUVDN2.js +0 -5127
  80. package/dist/dist-WLKUVDN2.js.map +0 -1
  81. package/dist/earthdistance-KIGTF4LE.js +0 -13
  82. package/dist/earthdistance-KIGTF4LE.js.map +0 -1
  83. package/dist/file_fdw-5N55UP6I.js +0 -13
  84. package/dist/file_fdw-5N55UP6I.js.map +0 -1
  85. package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
  86. package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
  87. package/dist/hstore-YX726NKN.js +0 -13
  88. package/dist/hstore-YX726NKN.js.map +0 -1
  89. package/dist/http-exception-FZY2H4OF.js +0 -8
  90. package/dist/http-exception-FZY2H4OF.js.map +0 -1
  91. package/dist/index.js +0 -30
  92. package/dist/index.js.map +0 -1
  93. package/dist/intarray-NKVXNO2D.js +0 -13
  94. package/dist/intarray-NKVXNO2D.js.map +0 -1
  95. package/dist/isn-FTEMJGEV.js +0 -13
  96. package/dist/isn-FTEMJGEV.js.map +0 -1
  97. package/dist/lo-DB7L4NGI.js +0 -13
  98. package/dist/lo-DB7L4NGI.js.map +0 -1
  99. package/dist/logger-WQ7SHNDD.js +0 -68
  100. package/dist/logger-WQ7SHNDD.js.map +0 -1
  101. package/dist/ltree-Z32TZT6W.js +0 -13
  102. package/dist/ltree-Z32TZT6W.js.map +0 -1
  103. package/dist/nodefs-NM46ACH7.js +0 -31
  104. package/dist/nodefs-NM46ACH7.js.map +0 -1
  105. package/dist/opfs-ahp-NJO33LVZ.js +0 -332
  106. package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
  107. package/dist/pageinspect-YP3IZR4X.js +0 -13
  108. package/dist/pageinspect-YP3IZR4X.js.map +0 -1
  109. package/dist/pg_buffercache-7TD5J2FB.js +0 -13
  110. package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
  111. package/dist/pg_dump-SG4KYBUB.js +0 -2492
  112. package/dist/pg_dump-SG4KYBUB.js.map +0 -1
  113. package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
  114. package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
  115. package/dist/pg_surgery-J2MUEWEP.js +0 -13
  116. package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
  117. package/dist/pg_trgm-7VNQOYS6.js +0 -13
  118. package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
  119. package/dist/pg_visibility-TTSIPHFL.js +0 -13
  120. package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
  121. package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
  122. package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
  123. package/dist/proxy-signals-GUDAMDHV.js +0 -39
  124. package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
  125. package/dist/seg-IYVDLE4O.js +0 -13
  126. package/dist/seg-IYVDLE4O.js.map +0 -1
  127. package/dist/src/codecs/decoding.d.ts +0 -4
  128. package/dist/src/codecs/decoding.d.ts.map +0 -1
  129. package/dist/src/codecs/encoding.d.ts +0 -5
  130. package/dist/src/codecs/encoding.d.ts.map +0 -1
  131. package/dist/src/codecs/validation.d.ts +0 -6
  132. package/dist/src/codecs/validation.d.ts.map +0 -1
  133. package/dist/src/exports/index.d.ts +0 -11
  134. package/dist/src/exports/index.d.ts.map +0 -1
  135. package/dist/src/index.d.ts +0 -2
  136. package/dist/src/index.d.ts.map +0 -1
  137. package/dist/src/lower-sql-plan.d.ts +0 -15
  138. package/dist/src/lower-sql-plan.d.ts.map +0 -1
  139. package/dist/src/sql-context.d.ts +0 -65
  140. package/dist/src/sql-context.d.ts.map +0 -1
  141. package/dist/src/sql-family-adapter.d.ts +0 -10
  142. package/dist/src/sql-family-adapter.d.ts.map +0 -1
  143. package/dist/src/sql-marker.d.ts +0 -22
  144. package/dist/src/sql-marker.d.ts.map +0 -1
  145. package/dist/src/sql-runtime.d.ts +0 -25
  146. package/dist/src/sql-runtime.d.ts.map +0 -1
  147. package/dist/tablefunc-EF4RCS7S.js +0 -13
  148. package/dist/tablefunc-EF4RCS7S.js.map +0 -1
  149. package/dist/tcn-3VT5BQYW.js +0 -13
  150. package/dist/tcn-3VT5BQYW.js.map +0 -1
  151. package/dist/test/utils.d.ts +0 -59
  152. package/dist/test/utils.d.ts.map +0 -1
  153. package/dist/test/utils.js +0 -24634
  154. package/dist/test/utils.js.map +0 -1
  155. package/dist/tiny-CW6F4GX6.js +0 -10
  156. package/dist/tiny-CW6F4GX6.js.map +0 -1
  157. package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
  158. package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
  159. package/dist/tsm_system_time-76WEIMBG.js +0 -13
  160. package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
  161. package/dist/unaccent-7RYF3R64.js +0 -13
  162. package/dist/unaccent-7RYF3R64.js.map +0 -1
  163. package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
  164. package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
  165. package/dist/uuid_ossp-4ETE4FPE.js +0 -13
  166. package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
  167. package/dist/vector-74GPNV7V.js +0 -13
  168. package/dist/vector-74GPNV7V.js.map +0 -1
  169. package/src/index.ts +0 -1
@@ -1,20 +1,25 @@
1
+ import { coreHash } from '@prisma-next/contract/types';
1
2
  import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
2
3
  import type { SqlOperationSignature } from '@prisma-next/sql-operations';
3
- import type { CodecRegistry, SelectAst } from '@prisma-next/sql-relational-core/ast';
4
4
  import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
5
5
  import { describe, expect, it } from 'vitest';
6
6
  import {
7
- createRuntimeContext,
7
+ createExecutionContext,
8
+ type SqlExecutionStack,
8
9
  type SqlRuntimeExtensionDescriptor,
9
- type SqlRuntimeExtensionInstance,
10
+ type SqlRuntimeTargetDescriptor,
10
11
  } from '../src/sql-context';
12
+ import {
13
+ createStubAdapter,
14
+ createTestAdapterDescriptor,
15
+ createTestTargetDescriptor,
16
+ } from './utils';
11
17
 
12
- // Minimal test contract
13
18
  const testContract: SqlContract<SqlStorage> = {
14
19
  schemaVersion: '1',
15
20
  targetFamily: 'sql',
16
21
  target: 'postgres',
17
- coreHash: 'sha256:test',
22
+ storageHash: coreHash('sha256:test'),
18
23
  models: {},
19
24
  relations: {},
20
25
  storage: { tables: {} },
@@ -22,82 +27,17 @@ const testContract: SqlContract<SqlStorage> = {
22
27
  capabilities: {},
23
28
  meta: {},
24
29
  sources: {},
25
- mappings: {
26
- codecTypes: {},
27
- operationTypes: {},
28
- },
30
+ mappings: {},
29
31
  };
30
32
 
31
- // Stub adapter codecs
32
- function createStubCodecs(): CodecRegistry {
33
- const registry = createCodecRegistry();
34
- registry.register(
35
- codec({
36
- typeId: 'pg/int4@1',
37
- targetTypes: ['int4'],
38
- encode: (v: number) => v,
39
- decode: (w: number) => w,
40
- }),
41
- );
42
- return registry;
43
- }
44
-
45
- // Create a test adapter descriptor
46
- function createTestAdapterDescriptor() {
47
- const codecs = createStubCodecs();
48
- return {
49
- kind: 'adapter' as const,
50
- id: 'test-adapter',
51
- version: '0.0.1',
52
- familyId: 'sql' as const,
53
- targetId: 'postgres' as const,
54
- create() {
55
- return {
56
- familyId: 'sql' as const,
57
- targetId: 'postgres' as const,
58
- profile: {
59
- id: 'test-profile',
60
- target: 'postgres',
61
- capabilities: {},
62
- codecs() {
63
- return codecs;
64
- },
65
- },
66
- lower(ast: SelectAst) {
67
- return {
68
- profileId: 'test-profile',
69
- body: Object.freeze({ sql: JSON.stringify(ast), params: [] }),
70
- };
71
- },
72
- };
73
- },
74
- };
75
- }
76
-
77
- // Create a test target descriptor
78
- function createTestTargetDescriptor() {
79
- return {
80
- kind: 'target' as const,
81
- id: 'postgres',
82
- version: '0.0.1',
83
- familyId: 'sql' as const,
84
- targetId: 'postgres' as const,
85
- create() {
86
- return { familyId: 'sql' as const, targetId: 'postgres' as const };
87
- },
88
- };
89
- }
90
-
91
- // Create a test extension descriptor
92
33
  function createTestExtensionDescriptor(options?: {
93
34
  hasCodecs?: boolean;
94
35
  hasOperations?: boolean;
95
36
  }): SqlRuntimeExtensionDescriptor<'postgres'> {
96
37
  const { hasCodecs = false, hasOperations = false } = options ?? {};
97
38
 
98
- // Build the codecs function if needed
99
- const codecsFn = hasCodecs
100
- ? () => {
39
+ const codecRegistry = hasCodecs
40
+ ? (() => {
101
41
  const registry = createCodecRegistry();
102
42
  registry.register(
103
43
  codec({
@@ -108,21 +48,24 @@ function createTestExtensionDescriptor(options?: {
108
48
  }),
109
49
  );
110
50
  return registry;
111
- }
112
- : undefined;
51
+ })()
52
+ : createCodecRegistry();
113
53
 
114
- // Build the operations function if needed
115
- const operationsFn = hasOperations
116
- ? (): ReadonlyArray<SqlOperationSignature> => [
54
+ const operationsArray: ReadonlyArray<SqlOperationSignature> = hasOperations
55
+ ? [
117
56
  {
118
57
  forTypeId: 'test/ext@1',
119
58
  method: 'testOp',
120
59
  args: [],
121
- returns: { kind: 'builtin', type: 'number' },
122
- lowering: { targetFamily: 'sql', strategy: 'function', template: 'test()' },
60
+ returns: { kind: 'builtin' as const, type: 'number' as const },
61
+ lowering: {
62
+ targetFamily: 'sql' as const,
63
+ strategy: 'function' as const,
64
+ template: 'test()',
65
+ },
123
66
  },
124
67
  ]
125
- : undefined;
68
+ : [];
126
69
 
127
70
  return {
128
71
  kind: 'extension' as const,
@@ -130,71 +73,68 @@ function createTestExtensionDescriptor(options?: {
130
73
  version: '0.0.1',
131
74
  familyId: 'sql' as const,
132
75
  targetId: 'postgres' as const,
133
- create(): SqlRuntimeExtensionInstance<'postgres'> {
134
- // Return object with optional methods only if they exist
135
- const instance: SqlRuntimeExtensionInstance<'postgres'> = {
76
+ codecs: () => codecRegistry,
77
+ operationSignatures: () => operationsArray,
78
+ parameterizedCodecs: () => [],
79
+ create() {
80
+ return {
136
81
  familyId: 'sql' as const,
137
82
  targetId: 'postgres' as const,
138
83
  };
139
- if (codecsFn) {
140
- (instance as { codecs?: () => CodecRegistry }).codecs = codecsFn;
141
- }
142
- if (operationsFn) {
143
- (instance as { operations?: () => ReadonlyArray<SqlOperationSignature> }).operations =
144
- operationsFn;
145
- }
146
- return instance;
147
84
  },
148
85
  };
149
86
  }
150
87
 
151
- describe('createRuntimeContext', () => {
152
- it('creates context with adapter codecs', () => {
153
- const context = createRuntimeContext({
88
+ function createStack(options?: {
89
+ extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;
90
+ }): SqlExecutionStack<'postgres'> {
91
+ return {
92
+ target: createTestTargetDescriptor(),
93
+ adapter: createTestAdapterDescriptor(createStubAdapter()),
94
+ extensionPacks: options?.extensionPacks ?? [],
95
+ };
96
+ }
97
+
98
+ describe('createExecutionContext', () => {
99
+ it('creates context with adapter codecs from descriptor', () => {
100
+ const context = createExecutionContext({
154
101
  contract: testContract,
155
- target: createTestTargetDescriptor(),
156
- adapter: createTestAdapterDescriptor(),
102
+ stack: createStack(),
157
103
  });
158
104
 
159
105
  expect(context.contract).toBe(testContract);
160
- expect(context.adapter).toBeDefined();
161
106
  expect(context.codecs.has('pg/int4@1')).toBe(true);
162
107
  expect(context.operations).toBeDefined();
163
108
  });
164
109
 
165
110
  it('creates context with empty extension packs', () => {
166
- const context = createRuntimeContext({
111
+ const context = createExecutionContext({
167
112
  contract: testContract,
168
- target: createTestTargetDescriptor(),
169
- adapter: createTestAdapterDescriptor(),
170
- extensionPacks: [],
113
+ stack: createStack({ extensionPacks: [] }),
171
114
  });
172
115
 
173
116
  expect(context.codecs.has('pg/int4@1')).toBe(true);
174
- // No extension codecs registered
175
117
  expect(context.codecs.has('test/ext@1')).toBe(false);
176
118
  });
177
119
 
178
- it('registers extension codecs', () => {
179
- const context = createRuntimeContext({
120
+ it('registers extension codecs from descriptors', () => {
121
+ const context = createExecutionContext({
180
122
  contract: testContract,
181
- target: createTestTargetDescriptor(),
182
- adapter: createTestAdapterDescriptor(),
183
- extensionPacks: [createTestExtensionDescriptor({ hasCodecs: true })],
123
+ stack: createStack({
124
+ extensionPacks: [createTestExtensionDescriptor({ hasCodecs: true })],
125
+ }),
184
126
  });
185
127
 
186
- // Adapter codec
187
128
  expect(context.codecs.has('pg/int4@1')).toBe(true);
188
- // Extension codec
189
129
  expect(context.codecs.has('test/ext@1')).toBe(true);
190
130
  });
191
131
 
192
- it('registers extension operations', () => {
193
- const context = createRuntimeContext({
132
+ it('registers extension operations from descriptors', () => {
133
+ const context = createExecutionContext({
194
134
  contract: testContract,
195
- target: createTestTargetDescriptor(),
196
- adapter: createTestAdapterDescriptor(),
197
- extensionPacks: [createTestExtensionDescriptor({ hasOperations: true })],
135
+ stack: createStack({
136
+ extensionPacks: [createTestExtensionDescriptor({ hasOperations: true })],
137
+ }),
198
138
  });
199
139
 
200
140
  const ops = context.operations.byType('test/ext@1');
@@ -202,16 +142,248 @@ describe('createRuntimeContext', () => {
202
142
  expect(ops[0]?.method).toBe('testOp');
203
143
  });
204
144
 
205
- it('handles extension without codecs or operations', () => {
206
- const context = createRuntimeContext({
145
+ it('handles extension with no contributions', () => {
146
+ const context = createExecutionContext({
207
147
  contract: testContract,
208
- target: createTestTargetDescriptor(),
209
- adapter: createTestAdapterDescriptor(),
210
- extensionPacks: [createTestExtensionDescriptor({ hasCodecs: false, hasOperations: false })],
148
+ stack: createStack({
149
+ extensionPacks: [createTestExtensionDescriptor({ hasCodecs: false, hasOperations: false })],
150
+ }),
211
151
  });
212
152
 
213
- // Only adapter codec
214
153
  expect(context.codecs.has('pg/int4@1')).toBe(true);
215
154
  expect(context.codecs.has('test/ext@1')).toBe(false);
216
155
  });
217
156
  });
157
+
158
+ describe('comprehensive descriptor-based derivation', () => {
159
+ it('includes all expected codec IDs and operations from target, adapter, and extensions', () => {
160
+ const targetCodecRegistry = createCodecRegistry();
161
+ targetCodecRegistry.register(
162
+ codec({
163
+ typeId: 'target/special@1',
164
+ targetTypes: ['special'],
165
+ encode: (v: string) => v,
166
+ decode: (w: string) => w,
167
+ }),
168
+ );
169
+
170
+ const targetOps: SqlOperationSignature[] = [
171
+ {
172
+ forTypeId: 'target/special@1',
173
+ method: 'targetOp',
174
+ args: [],
175
+ returns: { kind: 'builtin' as const, type: 'string' as const },
176
+ lowering: {
177
+ targetFamily: 'sql' as const,
178
+ strategy: 'function' as const,
179
+ template: 'target_fn()',
180
+ },
181
+ },
182
+ ];
183
+
184
+ const target: SqlRuntimeTargetDescriptor<'postgres'> = {
185
+ kind: 'target' as const,
186
+ id: 'postgres',
187
+ version: '0.0.1',
188
+ familyId: 'sql' as const,
189
+ targetId: 'postgres' as const,
190
+ codecs: () => targetCodecRegistry,
191
+ operationSignatures: () => targetOps,
192
+ parameterizedCodecs: () => [],
193
+ create() {
194
+ return { familyId: 'sql' as const, targetId: 'postgres' as const };
195
+ },
196
+ };
197
+
198
+ const stack: SqlExecutionStack<'postgres'> = {
199
+ target,
200
+ adapter: createTestAdapterDescriptor(createStubAdapter()),
201
+ extensionPacks: [createTestExtensionDescriptor({ hasCodecs: true, hasOperations: true })],
202
+ };
203
+
204
+ const context = createExecutionContext({ contract: testContract, stack });
205
+
206
+ expect(context.codecs.has('target/special@1')).toBe(true);
207
+ expect(context.codecs.has('pg/int4@1')).toBe(true);
208
+ expect(context.codecs.has('test/ext@1')).toBe(true);
209
+
210
+ expect(context.operations.byType('target/special@1').length).toBe(1);
211
+ expect(context.operations.byType('target/special@1')[0]?.method).toBe('targetOp');
212
+ expect(context.operations.byType('test/ext@1').length).toBe(1);
213
+ expect(context.operations.byType('test/ext@1')[0]?.method).toBe('testOp');
214
+ });
215
+ });
216
+
217
+ describe('context.types presence', () => {
218
+ it('exists as empty object when no parameterized codecs are registered', () => {
219
+ const context = createExecutionContext({
220
+ contract: testContract,
221
+ stack: createStack(),
222
+ });
223
+
224
+ expect(context.types).toBeDefined();
225
+ expect(context.types).toEqual({});
226
+ });
227
+ });
228
+
229
+ describe('contract/stack validation errors', () => {
230
+ it('throws RUNTIME.CONTRACT_FAMILY_MISMATCH when contract targetFamily differs from stack', () => {
231
+ const mismatchedFamilyContract = {
232
+ ...testContract,
233
+ targetFamily: 'document',
234
+ } as unknown as SqlContract<SqlStorage>;
235
+
236
+ expect(() =>
237
+ createExecutionContext({ contract: mismatchedFamilyContract, stack: createStack() }),
238
+ ).toThrow(
239
+ expect.objectContaining({
240
+ code: 'RUNTIME.CONTRACT_FAMILY_MISMATCH',
241
+ category: 'RUNTIME',
242
+ severity: 'error',
243
+ details: {
244
+ actual: 'document',
245
+ expected: 'sql',
246
+ },
247
+ }),
248
+ );
249
+ });
250
+
251
+ it('throws RUNTIME.CONTRACT_TARGET_MISMATCH when contract target differs from stack', () => {
252
+ const mismatchedContract: SqlContract<SqlStorage> = {
253
+ ...testContract,
254
+ target: 'mysql',
255
+ };
256
+
257
+ expect(() =>
258
+ createExecutionContext({ contract: mismatchedContract, stack: createStack() }),
259
+ ).toThrow(
260
+ expect.objectContaining({
261
+ code: 'RUNTIME.CONTRACT_TARGET_MISMATCH',
262
+ category: 'RUNTIME',
263
+ severity: 'error',
264
+ details: {
265
+ actual: 'mysql',
266
+ expected: 'postgres',
267
+ },
268
+ }),
269
+ );
270
+ });
271
+
272
+ it('throws RUNTIME.MISSING_EXTENSION_PACK when contract requires extension not in stack', () => {
273
+ const contractWithExtension: SqlContract<SqlStorage> = {
274
+ ...testContract,
275
+ extensionPacks: {
276
+ 'required-extension': { id: 'required-extension', version: '1.0.0', capabilities: {} },
277
+ },
278
+ };
279
+
280
+ expect(() =>
281
+ createExecutionContext({ contract: contractWithExtension, stack: createStack() }),
282
+ ).toThrow(
283
+ expect.objectContaining({
284
+ code: 'RUNTIME.MISSING_EXTENSION_PACK',
285
+ category: 'RUNTIME',
286
+ severity: 'error',
287
+ details: {
288
+ packIds: ['required-extension'],
289
+ },
290
+ }),
291
+ );
292
+ });
293
+
294
+ it('lists all missing extension packs in a single error', () => {
295
+ const contractWithExtensions: SqlContract<SqlStorage> = {
296
+ ...testContract,
297
+ extensionPacks: {
298
+ 'ext-a': { id: 'ext-a', version: '1.0.0', capabilities: {} },
299
+ 'ext-b': { id: 'ext-b', version: '1.0.0', capabilities: {} },
300
+ },
301
+ };
302
+
303
+ expect(() =>
304
+ createExecutionContext({ contract: contractWithExtensions, stack: createStack() }),
305
+ ).toThrow(
306
+ expect.objectContaining({
307
+ code: 'RUNTIME.MISSING_EXTENSION_PACK',
308
+ details: {
309
+ packIds: expect.arrayContaining(['ext-a', 'ext-b']),
310
+ },
311
+ }),
312
+ );
313
+ });
314
+ });
315
+
316
+ describe('applyMutationDefaults', () => {
317
+ const contractWithDefaults: SqlContract<SqlStorage> = {
318
+ ...testContract,
319
+ storage: {
320
+ tables: {
321
+ user: {
322
+ columns: {
323
+ id: { nativeType: 'text', codecId: 'pg/text@1', nullable: false },
324
+ slug: { nativeType: 'text', codecId: 'pg/text@1', nullable: false },
325
+ },
326
+ uniques: [],
327
+ indexes: [],
328
+ foreignKeys: [],
329
+ },
330
+ },
331
+ },
332
+ execution: {
333
+ mutations: {
334
+ defaults: [
335
+ {
336
+ ref: { table: 'user', column: 'id' },
337
+ onCreate: { kind: 'generator', id: 'nanoid', params: { size: 8 } },
338
+ },
339
+ {
340
+ ref: { table: 'user', column: 'slug' },
341
+ onUpdate: { kind: 'generator', id: 'nanoid', params: { size: 6 } },
342
+ },
343
+ ],
344
+ },
345
+ },
346
+ };
347
+
348
+ it('applies create defaults with generator params', () => {
349
+ const context = createExecutionContext({
350
+ contract: contractWithDefaults,
351
+ stack: createStack(),
352
+ });
353
+
354
+ const applied = context.applyMutationDefaults({
355
+ op: 'create',
356
+ table: 'user',
357
+ values: {},
358
+ });
359
+
360
+ expect(applied).toEqual([
361
+ {
362
+ column: 'id',
363
+ value: expect.any(String),
364
+ },
365
+ ]);
366
+ expect((applied[0]?.value as string).length).toBe(8);
367
+ });
368
+
369
+ it('applies update defaults from onUpdate', () => {
370
+ const context = createExecutionContext({
371
+ contract: contractWithDefaults,
372
+ stack: createStack(),
373
+ });
374
+
375
+ const applied = context.applyMutationDefaults({
376
+ op: 'update',
377
+ table: 'user',
378
+ values: {},
379
+ });
380
+
381
+ expect(applied).toEqual([
382
+ {
383
+ column: 'slug',
384
+ value: expect.any(String),
385
+ },
386
+ ]);
387
+ expect((applied[0]?.value as string).length).toBe(6);
388
+ });
389
+ });
@@ -1,4 +1,5 @@
1
1
  import type { ExecutionPlan } from '@prisma-next/contract/types';
2
+ import { coreHash } from '@prisma-next/contract/types';
2
3
  import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
3
4
  import { describe, expect, it } from 'vitest';
4
5
  import { SqlFamilyAdapter } from '../src/sql-family-adapter';
@@ -8,7 +9,7 @@ const testContract: SqlContract<SqlStorage> = {
8
9
  schemaVersion: '1',
9
10
  targetFamily: 'sql',
10
11
  target: 'postgres',
11
- coreHash: 'sha256:test-hash',
12
+ storageHash: coreHash('sha256:test-hash'),
12
13
  models: {},
13
14
  relations: {},
14
15
  storage: { tables: {} },
@@ -16,10 +17,7 @@ const testContract: SqlContract<SqlStorage> = {
16
17
  capabilities: {},
17
18
  meta: {},
18
19
  sources: {},
19
- mappings: {
20
- codecTypes: {},
21
- operationTypes: {},
22
- },
20
+ mappings: {},
23
21
  };
24
22
 
25
23
  describe('SqlFamilyAdapter', () => {
@@ -36,7 +34,7 @@ describe('SqlFamilyAdapter', () => {
36
34
  const plan: ExecutionPlan = {
37
35
  meta: {
38
36
  target: 'postgres',
39
- coreHash: 'sha256:test-hash',
37
+ storageHash: 'sha256:test-hash',
40
38
  lane: 'sql',
41
39
  paramDescriptors: [],
42
40
  },
@@ -53,7 +51,7 @@ describe('SqlFamilyAdapter', () => {
53
51
  const plan: ExecutionPlan = {
54
52
  meta: {
55
53
  target: 'mysql', // Wrong target
56
- coreHash: 'sha256:test-hash',
54
+ storageHash: 'sha256:test-hash',
57
55
  lane: 'sql',
58
56
  paramDescriptors: [],
59
57
  },
@@ -66,12 +64,12 @@ describe('SqlFamilyAdapter', () => {
66
64
  );
67
65
  });
68
66
 
69
- it('throws on plan coreHash mismatch', () => {
67
+ it('throws on plan storageHash mismatch', () => {
70
68
  const adapter = new SqlFamilyAdapter(testContract);
71
69
  const plan: ExecutionPlan = {
72
70
  meta: {
73
71
  target: 'postgres',
74
- coreHash: 'sha256:different-hash', // Wrong hash
72
+ storageHash: 'sha256:different-hash', // Wrong hash
75
73
  lane: 'sql',
76
74
  paramDescriptors: [],
77
75
  },
@@ -80,7 +78,7 @@ describe('SqlFamilyAdapter', () => {
80
78
  };
81
79
 
82
80
  expect(() => adapter.validatePlan(plan, testContract)).toThrow(
83
- 'Plan core hash does not match runtime contract',
81
+ 'Plan storage hash does not match runtime contract',
84
82
  );
85
83
  });
86
84
  });