@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.
- package/LICENSE +201 -0
- package/README.md +141 -24
- package/dist/exports-BKjZvwMh.mjs +971 -0
- package/dist/exports-BKjZvwMh.mjs.map +1 -0
- package/dist/index-eHiENgIB.d.mts +182 -0
- package/dist/index-eHiENgIB.d.mts.map +1 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +3 -0
- package/dist/test/utils.d.mts +82 -0
- package/dist/test/utils.d.mts.map +1 -0
- package/dist/test/utils.mjs +221 -0
- package/dist/test/utils.mjs.map +1 -0
- package/package.json +29 -22
- package/src/codecs/decoding.ts +84 -3
- package/src/codecs/encoding.ts +5 -15
- package/src/codecs/json-schema-validation.ts +61 -0
- package/src/exports/index.ts +19 -7
- package/src/lower-sql-plan.ts +8 -8
- package/src/plugins/budgets.ts +375 -0
- package/src/plugins/lints.ts +211 -0
- package/src/sql-context.ts +448 -98
- package/src/sql-family-adapter.ts +9 -5
- package/src/sql-marker.ts +2 -2
- package/src/sql-runtime.ts +126 -30
- package/test/async-iterable-result.test.ts +43 -35
- package/test/budgets.test.ts +481 -0
- package/test/context.types.test-d.ts +68 -0
- package/test/execution-stack.test.ts +166 -0
- package/test/json-schema-validation.test.ts +575 -0
- package/test/lints.test.ts +161 -0
- package/test/mutation-default-generators.test.ts +256 -0
- package/test/parameterized-types.test.ts +536 -0
- package/test/sql-context.test.ts +293 -121
- package/test/sql-family-adapter.test.ts +8 -10
- package/test/sql-runtime.test.ts +219 -34
- package/test/utils.ts +90 -51
- package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
- package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
- package/dist/amcheck-24VY6X5V.js +0 -13
- package/dist/amcheck-24VY6X5V.js.map +0 -1
- package/dist/bloom-VS74NLHT.js +0 -13
- package/dist/bloom-VS74NLHT.js.map +0 -1
- package/dist/btree_gin-WBC4EAAI.js +0 -13
- package/dist/btree_gin-WBC4EAAI.js.map +0 -1
- package/dist/btree_gist-UNC6QD3M.js +0 -13
- package/dist/btree_gist-UNC6QD3M.js.map +0 -1
- package/dist/chunk-3KTOEDFX.js +0 -49
- package/dist/chunk-3KTOEDFX.js.map +0 -1
- package/dist/chunk-47DZBRQC.js +0 -1280
- package/dist/chunk-47DZBRQC.js.map +0 -1
- package/dist/chunk-52N6AFZM.js +0 -133
- package/dist/chunk-52N6AFZM.js.map +0 -1
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-7D4SUZUM.js.map +0 -1
- package/dist/chunk-C6I3V3DM.js +0 -455
- package/dist/chunk-C6I3V3DM.js.map +0 -1
- package/dist/chunk-ECWIHLAT.js +0 -37
- package/dist/chunk-ECWIHLAT.js.map +0 -1
- package/dist/chunk-EI626SDC.js +0 -105
- package/dist/chunk-EI626SDC.js.map +0 -1
- package/dist/chunk-UKKOYUGL.js +0 -578
- package/dist/chunk-UKKOYUGL.js.map +0 -1
- package/dist/chunk-XPLNMXQV.js +0 -1537
- package/dist/chunk-XPLNMXQV.js.map +0 -1
- package/dist/citext-T7MXGUY7.js +0 -13
- package/dist/citext-T7MXGUY7.js.map +0 -1
- package/dist/client-5FENX6AW.js +0 -299
- package/dist/client-5FENX6AW.js.map +0 -1
- package/dist/cube-TFDQBZCI.js +0 -13
- package/dist/cube-TFDQBZCI.js.map +0 -1
- package/dist/dict_int-AEUOPGWP.js +0 -13
- package/dist/dict_int-AEUOPGWP.js.map +0 -1
- package/dist/dict_xsyn-DAAYX3FL.js +0 -13
- package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
- package/dist/dist-AQ3LWXOX.js +0 -570
- package/dist/dist-AQ3LWXOX.js.map +0 -1
- package/dist/dist-LBVX6BJW.js +0 -189
- package/dist/dist-LBVX6BJW.js.map +0 -1
- package/dist/dist-WLKUVDN2.js +0 -5127
- package/dist/dist-WLKUVDN2.js.map +0 -1
- package/dist/earthdistance-KIGTF4LE.js +0 -13
- package/dist/earthdistance-KIGTF4LE.js.map +0 -1
- package/dist/file_fdw-5N55UP6I.js +0 -13
- package/dist/file_fdw-5N55UP6I.js.map +0 -1
- package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
- package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
- package/dist/hstore-YX726NKN.js +0 -13
- package/dist/hstore-YX726NKN.js.map +0 -1
- package/dist/http-exception-FZY2H4OF.js +0 -8
- package/dist/http-exception-FZY2H4OF.js.map +0 -1
- package/dist/index.js +0 -30
- package/dist/index.js.map +0 -1
- package/dist/intarray-NKVXNO2D.js +0 -13
- package/dist/intarray-NKVXNO2D.js.map +0 -1
- package/dist/isn-FTEMJGEV.js +0 -13
- package/dist/isn-FTEMJGEV.js.map +0 -1
- package/dist/lo-DB7L4NGI.js +0 -13
- package/dist/lo-DB7L4NGI.js.map +0 -1
- package/dist/logger-WQ7SHNDD.js +0 -68
- package/dist/logger-WQ7SHNDD.js.map +0 -1
- package/dist/ltree-Z32TZT6W.js +0 -13
- package/dist/ltree-Z32TZT6W.js.map +0 -1
- package/dist/nodefs-NM46ACH7.js +0 -31
- package/dist/nodefs-NM46ACH7.js.map +0 -1
- package/dist/opfs-ahp-NJO33LVZ.js +0 -332
- package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
- package/dist/pageinspect-YP3IZR4X.js +0 -13
- package/dist/pageinspect-YP3IZR4X.js.map +0 -1
- package/dist/pg_buffercache-7TD5J2FB.js +0 -13
- package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
- package/dist/pg_dump-SG4KYBUB.js +0 -2492
- package/dist/pg_dump-SG4KYBUB.js.map +0 -1
- package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
- package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
- package/dist/pg_surgery-J2MUEWEP.js +0 -13
- package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
- package/dist/pg_trgm-7VNQOYS6.js +0 -13
- package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
- package/dist/pg_visibility-TTSIPHFL.js +0 -13
- package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
- package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
- package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
- package/dist/proxy-signals-GUDAMDHV.js +0 -39
- package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
- package/dist/seg-IYVDLE4O.js +0 -13
- package/dist/seg-IYVDLE4O.js.map +0 -1
- package/dist/src/codecs/decoding.d.ts +0 -4
- package/dist/src/codecs/decoding.d.ts.map +0 -1
- package/dist/src/codecs/encoding.d.ts +0 -5
- package/dist/src/codecs/encoding.d.ts.map +0 -1
- package/dist/src/codecs/validation.d.ts +0 -6
- package/dist/src/codecs/validation.d.ts.map +0 -1
- package/dist/src/exports/index.d.ts +0 -11
- package/dist/src/exports/index.d.ts.map +0 -1
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/lower-sql-plan.d.ts +0 -15
- package/dist/src/lower-sql-plan.d.ts.map +0 -1
- package/dist/src/sql-context.d.ts +0 -65
- package/dist/src/sql-context.d.ts.map +0 -1
- package/dist/src/sql-family-adapter.d.ts +0 -10
- package/dist/src/sql-family-adapter.d.ts.map +0 -1
- package/dist/src/sql-marker.d.ts +0 -22
- package/dist/src/sql-marker.d.ts.map +0 -1
- package/dist/src/sql-runtime.d.ts +0 -25
- package/dist/src/sql-runtime.d.ts.map +0 -1
- package/dist/tablefunc-EF4RCS7S.js +0 -13
- package/dist/tablefunc-EF4RCS7S.js.map +0 -1
- package/dist/tcn-3VT5BQYW.js +0 -13
- package/dist/tcn-3VT5BQYW.js.map +0 -1
- package/dist/test/utils.d.ts +0 -59
- package/dist/test/utils.d.ts.map +0 -1
- package/dist/test/utils.js +0 -24634
- package/dist/test/utils.js.map +0 -1
- package/dist/tiny-CW6F4GX6.js +0 -10
- package/dist/tiny-CW6F4GX6.js.map +0 -1
- package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
- package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
- package/dist/tsm_system_time-76WEIMBG.js +0 -13
- package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
- package/dist/unaccent-7RYF3R64.js +0 -13
- package/dist/unaccent-7RYF3R64.js.map +0 -1
- package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
- package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
- package/dist/uuid_ossp-4ETE4FPE.js +0 -13
- package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
- package/dist/vector-74GPNV7V.js +0 -13
- package/dist/vector-74GPNV7V.js.map +0 -1
- package/src/index.ts +0 -1
package/test/sql-context.test.ts
CHANGED
|
@@ -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
|
-
|
|
7
|
+
createExecutionContext,
|
|
8
|
+
type SqlExecutionStack,
|
|
8
9
|
type SqlRuntimeExtensionDescriptor,
|
|
9
|
-
type
|
|
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
|
-
|
|
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
|
-
|
|
99
|
-
|
|
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
|
-
:
|
|
51
|
+
})()
|
|
52
|
+
: createCodecRegistry();
|
|
113
53
|
|
|
114
|
-
|
|
115
|
-
|
|
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: {
|
|
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
|
-
:
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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 =
|
|
111
|
+
const context = createExecutionContext({
|
|
167
112
|
contract: testContract,
|
|
168
|
-
|
|
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 =
|
|
120
|
+
it('registers extension codecs from descriptors', () => {
|
|
121
|
+
const context = createExecutionContext({
|
|
180
122
|
contract: testContract,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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 =
|
|
132
|
+
it('registers extension operations from descriptors', () => {
|
|
133
|
+
const context = createExecutionContext({
|
|
194
134
|
contract: testContract,
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
|
206
|
-
const context =
|
|
145
|
+
it('handles extension with no contributions', () => {
|
|
146
|
+
const context = createExecutionContext({
|
|
207
147
|
contract: testContract,
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
81
|
+
'Plan storage hash does not match runtime contract',
|
|
84
82
|
);
|
|
85
83
|
});
|
|
86
84
|
});
|