@prisma-next/sql-runtime 0.3.0-dev.11 → 0.3.0-dev.114

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