@prisma-next/sql-runtime 0.3.0-dev.7 → 0.3.0-dev.71

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