@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.
- package/LICENSE +201 -0
- package/README.md +137 -26
- package/dist/exports-BhZqJPVb.mjs +771 -0
- package/dist/exports-BhZqJPVb.mjs.map +1 -0
- package/dist/index-D59jqEKF.d.mts +159 -0
- package/dist/index-D59jqEKF.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 +212 -0
- package/dist/test/utils.mjs.map +1 -0
- package/package.json +32 -25
- package/src/codecs/decoding.ts +84 -3
- package/src/codecs/encoding.ts +15 -2
- package/src/codecs/json-schema-validation.ts +61 -0
- package/src/exports/index.ts +14 -6
- package/src/lower-sql-plan.ts +8 -8
- package/src/plugins/lints.ts +204 -0
- package/src/sql-context.ts +385 -98
- package/src/sql-family-adapter.ts +9 -5
- package/src/sql-marker.ts +2 -2
- package/src/sql-runtime.ts +131 -31
- package/test/async-iterable-result.test.ts +42 -34
- package/test/context.types.test-d.ts +68 -0
- package/test/execution-stack.test.ts +166 -0
- package/test/json-schema-validation.test.ts +653 -0
- package/test/lints.test.ts +330 -0
- package/test/parameterized-types.test.ts +539 -0
- package/test/sql-context.test.ts +292 -117
- package/test/sql-family-adapter.test.ts +7 -6
- package/test/sql-runtime.test.ts +218 -30
- package/test/utils.ts +80 -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: {} },
|
|
@@ -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
|
-
|
|
99
|
-
|
|
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
|
-
:
|
|
54
|
+
})()
|
|
55
|
+
: createCodecRegistry();
|
|
113
56
|
|
|
114
|
-
|
|
115
|
-
|
|
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: {
|
|
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
|
-
:
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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 =
|
|
114
|
+
const context = createExecutionContext({
|
|
167
115
|
contract: testContract,
|
|
168
|
-
|
|
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 =
|
|
123
|
+
it('registers extension codecs from descriptors', () => {
|
|
124
|
+
const context = createExecutionContext({
|
|
180
125
|
contract: testContract,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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 =
|
|
135
|
+
it('registers extension operations from descriptors', () => {
|
|
136
|
+
const context = createExecutionContext({
|
|
194
137
|
contract: testContract,
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
|
206
|
-
const context =
|
|
148
|
+
it('handles extension with no contributions', () => {
|
|
149
|
+
const context = createExecutionContext({
|
|
207
150
|
contract: testContract,
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
84
|
+
'Plan storage hash does not match runtime contract',
|
|
84
85
|
);
|
|
85
86
|
});
|
|
86
87
|
});
|