@prisma-next/sql-runtime 0.3.0-pr.99.5 → 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
@@ -0,0 +1,159 @@
1
+ import type { ExecutionPlan, PlanMeta } from '@prisma-next/contract/types';
2
+ import type { MiddlewareContext } from '@prisma-next/runtime-executor';
3
+ import {
4
+ BinaryExpr,
5
+ ColumnRef,
6
+ DeleteAst,
7
+ DerivedTableSource,
8
+ ParamRef,
9
+ ProjectionItem,
10
+ SelectAst,
11
+ TableSource,
12
+ UpdateAst,
13
+ } from '@prisma-next/sql-relational-core/ast';
14
+ import { timeouts } from '@prisma-next/test-utils';
15
+ import { describe, expect, it, vi } from 'vitest';
16
+ import { lints } from '../src/middleware/lints';
17
+
18
+ function createMiddlewareContext(): MiddlewareContext<unknown> {
19
+ return {
20
+ contract: {},
21
+ mode: 'strict' as const,
22
+ now: () => Date.now(),
23
+ log: {
24
+ info: vi.fn(),
25
+ warn: vi.fn(),
26
+ error: vi.fn(),
27
+ },
28
+ };
29
+ }
30
+
31
+ const baseMeta: PlanMeta = {
32
+ target: 'postgres',
33
+ storageHash: 'sha256:test',
34
+ lane: 'dsl',
35
+ paramDescriptors: [],
36
+ };
37
+
38
+ type PlanOverrides = Partial<Omit<ExecutionPlan, 'meta'>> & { meta?: Partial<PlanMeta> };
39
+
40
+ function createPlan(overrides: PlanOverrides): ExecutionPlan {
41
+ const { meta: metaOverrides, ...rest } = overrides;
42
+ return {
43
+ sql: 'SELECT 1',
44
+ params: [],
45
+ meta: { ...baseMeta, ...(metaOverrides ?? {}) } as PlanMeta,
46
+ ...rest,
47
+ } as ExecutionPlan;
48
+ }
49
+
50
+ const userTable = TableSource.named('user');
51
+ const idCol = ColumnRef.of('user', 'id');
52
+
53
+ describe('lints middleware', () => {
54
+ it(
55
+ 'blocks delete without where',
56
+ async () => {
57
+ const plan = createPlan({ ast: DeleteAst.from(userTable) });
58
+ const mw = lints();
59
+ const ctx = createMiddlewareContext();
60
+
61
+ await expect(mw.beforeExecute?.(plan, ctx)).rejects.toMatchObject({
62
+ code: 'LINT.DELETE_WITHOUT_WHERE',
63
+ details: { table: 'user' },
64
+ });
65
+ },
66
+ timeouts.default,
67
+ );
68
+
69
+ it(
70
+ 'blocks update without where',
71
+ async () => {
72
+ const plan = createPlan({
73
+ ast: UpdateAst.table(userTable).withSet({
74
+ email: ParamRef.of('new@example.com', { name: 'email', codecId: 'pg/text@1' }),
75
+ }),
76
+ });
77
+ const mw = lints();
78
+ const ctx = createMiddlewareContext();
79
+
80
+ await expect(mw.beforeExecute?.(plan, ctx)).rejects.toMatchObject({
81
+ code: 'LINT.UPDATE_WITHOUT_WHERE',
82
+ details: { table: 'user' },
83
+ });
84
+ },
85
+ timeouts.default,
86
+ );
87
+
88
+ it(
89
+ 'warns for unbounded selects and selectAll intent',
90
+ async () => {
91
+ const ast = SelectAst.from(userTable)
92
+ .withProjection([ProjectionItem.of('id', idCol)])
93
+ .withSelectAllIntent({ table: 'user' });
94
+ const plan = createPlan({ ast });
95
+ const mw = lints();
96
+ const ctx = createMiddlewareContext();
97
+
98
+ await mw.beforeExecute?.(plan, ctx);
99
+ expect(ctx.log.warn).toHaveBeenCalledWith(
100
+ expect.objectContaining({ code: 'LINT.NO_LIMIT', details: { table: 'user' } }),
101
+ );
102
+ expect(ctx.log.warn).toHaveBeenCalledWith(
103
+ expect.objectContaining({ code: 'LINT.SELECT_STAR', details: { table: 'user' } }),
104
+ );
105
+ },
106
+ timeouts.default,
107
+ );
108
+
109
+ it(
110
+ 'uses derived table aliases when reporting unbounded selects',
111
+ async () => {
112
+ const derived = DerivedTableSource.as(
113
+ 'user_ids',
114
+ SelectAst.from(userTable).withProjection([ProjectionItem.of('id', idCol)]),
115
+ );
116
+ const ast = SelectAst.from(derived).withProjection([
117
+ ProjectionItem.of('id', ColumnRef.of('user_ids', 'id')),
118
+ ]);
119
+ const plan = createPlan({ ast });
120
+ const mw = lints();
121
+ const ctx = createMiddlewareContext();
122
+
123
+ await mw.beforeExecute?.(plan, ctx);
124
+ expect(ctx.log.warn).toHaveBeenCalledWith(
125
+ expect.objectContaining({
126
+ code: 'LINT.NO_LIMIT',
127
+ details: { table: 'user_ids' },
128
+ }),
129
+ );
130
+ },
131
+ timeouts.default,
132
+ );
133
+
134
+ it(
135
+ 'allows bounded selects and guarded mutations',
136
+ async () => {
137
+ const selectPlan = createPlan({
138
+ ast: SelectAst.from(userTable)
139
+ .withProjection([ProjectionItem.of('id', idCol)])
140
+ .withWhere(BinaryExpr.eq(idCol, ParamRef.of(42, { codecId: 'pg/int4@1' })))
141
+ .withLimit(10),
142
+ });
143
+ const updatePlan = createPlan({
144
+ ast: UpdateAst.table(userTable)
145
+ .withSet({
146
+ email: ParamRef.of('new@example.com', { name: 'email', codecId: 'pg/text@1' }),
147
+ })
148
+ .withWhere(BinaryExpr.eq(idCol, ParamRef.of(1, { name: 'id', codecId: 'pg/int4@1' }))),
149
+ });
150
+ const mw = lints();
151
+ const ctx = createMiddlewareContext();
152
+
153
+ await mw.beforeExecute?.(selectPlan, ctx);
154
+ await mw.beforeExecute?.(updatePlan, ctx);
155
+ expect(ctx.log.warn).not.toHaveBeenCalled();
156
+ },
157
+ timeouts.default,
158
+ );
159
+ });
@@ -0,0 +1,254 @@
1
+ import { type Contract, coreHash, executionHash, profileHash } from '@prisma-next/contract/types';
2
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
3
+ import { createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
4
+ import { describe, expect, it } from 'vitest';
5
+ import {
6
+ createExecutionContext,
7
+ type SqlExecutionStack,
8
+ type SqlRuntimeExtensionDescriptor,
9
+ } from '../src/sql-context';
10
+ import {
11
+ createStubAdapter,
12
+ createTestAdapterDescriptor,
13
+ createTestTargetDescriptor,
14
+ } from './utils';
15
+
16
+ const testContract: Contract<SqlStorage> = {
17
+ targetFamily: 'sql',
18
+ target: 'postgres',
19
+ profileHash: profileHash('sha256:test'),
20
+ models: {},
21
+ roots: {},
22
+ storage: {
23
+ storageHash: coreHash('sha256:test'),
24
+ tables: {
25
+ user: {
26
+ columns: {
27
+ id: { nativeType: 'text', codecId: 'pg/text@1', nullable: false },
28
+ },
29
+ uniques: [],
30
+ indexes: [],
31
+ foreignKeys: [],
32
+ },
33
+ },
34
+ },
35
+ extensionPacks: {},
36
+ capabilities: {},
37
+ meta: {},
38
+ };
39
+
40
+ function createStack(
41
+ extensionPacks: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>,
42
+ ): SqlExecutionStack<'postgres'> {
43
+ return {
44
+ target: createTestTargetDescriptor(),
45
+ adapter: createTestAdapterDescriptor(createStubAdapter()),
46
+ extensionPacks,
47
+ };
48
+ }
49
+
50
+ describe('composed runtime mutation default generators', () => {
51
+ it('resolves a pack-contributed generator id', () => {
52
+ const extension: SqlRuntimeExtensionDescriptor<'postgres'> = {
53
+ kind: 'extension',
54
+ id: 'test-mutation-defaults',
55
+ version: '0.0.1',
56
+ familyId: 'sql',
57
+ targetId: 'postgres',
58
+ codecs: () => createCodecRegistry(),
59
+ parameterizedCodecs: () => [],
60
+ mutationDefaultGenerators: () => [
61
+ {
62
+ id: 'slugid',
63
+ generate: () => 'slug-from-pack',
64
+ },
65
+ ],
66
+ create() {
67
+ return { familyId: 'sql', targetId: 'postgres' };
68
+ },
69
+ };
70
+
71
+ const context = createExecutionContext({
72
+ contract: {
73
+ ...testContract,
74
+ execution: {
75
+ executionHash: executionHash('sha256:test'),
76
+ mutations: {
77
+ defaults: [
78
+ {
79
+ ref: { table: 'user', column: 'id' },
80
+ onCreate: { kind: 'generator', id: 'slugid' },
81
+ },
82
+ ],
83
+ },
84
+ },
85
+ },
86
+ stack: createStack([extension]),
87
+ });
88
+
89
+ const applied = context.applyMutationDefaults({ op: 'create', table: 'user', values: {} });
90
+ expect(applied).toEqual([{ column: 'id', value: 'slug-from-pack' }]);
91
+ });
92
+
93
+ it('skips generated default when user provides an explicit value', () => {
94
+ const extension: SqlRuntimeExtensionDescriptor<'postgres'> = {
95
+ kind: 'extension',
96
+ id: 'test-mutation-defaults',
97
+ version: '0.0.1',
98
+ familyId: 'sql',
99
+ targetId: 'postgres',
100
+ codecs: () => createCodecRegistry(),
101
+ parameterizedCodecs: () => [],
102
+ mutationDefaultGenerators: () => [
103
+ {
104
+ id: 'slugid',
105
+ generate: () => 'slug-from-pack',
106
+ },
107
+ ],
108
+ create() {
109
+ return { familyId: 'sql', targetId: 'postgres' };
110
+ },
111
+ };
112
+
113
+ const context = createExecutionContext({
114
+ contract: {
115
+ ...testContract,
116
+ execution: {
117
+ executionHash: executionHash('sha256:test'),
118
+ mutations: {
119
+ defaults: [
120
+ {
121
+ ref: { table: 'user', column: 'id' },
122
+ onCreate: { kind: 'generator', id: 'slugid' },
123
+ },
124
+ ],
125
+ },
126
+ },
127
+ },
128
+ stack: createStack([extension]),
129
+ });
130
+
131
+ const applied = context.applyMutationDefaults({
132
+ op: 'create',
133
+ table: 'user',
134
+ values: { id: 'user-provided-value' },
135
+ });
136
+ expect(applied).toEqual([]);
137
+ });
138
+
139
+ it('throws error naming both owners when duplicate generator ids are composed', () => {
140
+ const first: SqlRuntimeExtensionDescriptor<'postgres'> = {
141
+ kind: 'extension',
142
+ id: 'first-pack',
143
+ version: '0.0.1',
144
+ familyId: 'sql',
145
+ targetId: 'postgres',
146
+ codecs: () => createCodecRegistry(),
147
+ parameterizedCodecs: () => [],
148
+ mutationDefaultGenerators: () => [{ id: 'duplicate', generate: () => 'first' }],
149
+ create() {
150
+ return { familyId: 'sql', targetId: 'postgres' };
151
+ },
152
+ };
153
+ const second: SqlRuntimeExtensionDescriptor<'postgres'> = {
154
+ kind: 'extension',
155
+ id: 'second-pack',
156
+ version: '0.0.1',
157
+ familyId: 'sql',
158
+ targetId: 'postgres',
159
+ codecs: () => createCodecRegistry(),
160
+ parameterizedCodecs: () => [],
161
+ mutationDefaultGenerators: () => [{ id: 'duplicate', generate: () => 'second' }],
162
+ create() {
163
+ return { familyId: 'sql', targetId: 'postgres' };
164
+ },
165
+ };
166
+
167
+ expect(() =>
168
+ createExecutionContext({
169
+ contract: testContract,
170
+ stack: createStack([first, second]),
171
+ }),
172
+ ).toThrow(
173
+ expect.objectContaining({
174
+ code: 'RUNTIME.DUPLICATE_MUTATION_DEFAULT_GENERATOR',
175
+ details: expect.objectContaining({
176
+ existingOwner: 'first-pack',
177
+ incomingOwner: 'second-pack',
178
+ }),
179
+ }),
180
+ );
181
+ });
182
+
183
+ it('throws stable error when generator id implementation is missing', () => {
184
+ const context = createExecutionContext({
185
+ contract: {
186
+ ...testContract,
187
+ execution: {
188
+ executionHash: executionHash('sha256:test'),
189
+ mutations: {
190
+ defaults: [
191
+ {
192
+ ref: { table: 'user', column: 'id' },
193
+ onCreate: { kind: 'generator', id: 'unknown-generator' },
194
+ },
195
+ ],
196
+ },
197
+ },
198
+ },
199
+ stack: createStack([]),
200
+ });
201
+
202
+ expect(() =>
203
+ context.applyMutationDefaults({
204
+ op: 'create',
205
+ table: 'user',
206
+ values: {},
207
+ }),
208
+ ).toThrow(
209
+ expect.objectContaining({
210
+ code: 'RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING',
211
+ }),
212
+ );
213
+ });
214
+
215
+ it('does not resolve built-in generator ids without composed contributors', () => {
216
+ const adapterWithoutMutationDefaultGenerators = {
217
+ ...createTestAdapterDescriptor(createStubAdapter()),
218
+ mutationDefaultGenerators: () => [],
219
+ };
220
+ const context = createExecutionContext({
221
+ contract: {
222
+ ...testContract,
223
+ execution: {
224
+ executionHash: executionHash('sha256:test'),
225
+ mutations: {
226
+ defaults: [
227
+ {
228
+ ref: { table: 'user', column: 'id' },
229
+ onCreate: { kind: 'generator', id: 'uuidv4' },
230
+ },
231
+ ],
232
+ },
233
+ },
234
+ },
235
+ stack: {
236
+ target: createTestTargetDescriptor(),
237
+ adapter: adapterWithoutMutationDefaultGenerators,
238
+ extensionPacks: [],
239
+ },
240
+ });
241
+
242
+ expect(() =>
243
+ context.applyMutationDefaults({
244
+ op: 'create',
245
+ table: 'user',
246
+ values: {},
247
+ }),
248
+ ).toThrow(
249
+ expect.objectContaining({
250
+ code: 'RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING',
251
+ }),
252
+ );
253
+ });
254
+ });