@prisma-next/sql-runtime 0.3.0-pr.99.6 → 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.
- package/LICENSE +201 -0
- package/README.md +141 -24
- package/dist/exports-BO6Fl7yn.mjs +889 -0
- package/dist/exports-BO6Fl7yn.mjs.map +1 -0
- package/dist/index-n6z6trta.d.mts +186 -0
- package/dist/index-n6z6trta.d.mts.map +1 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +3 -0
- package/dist/test/utils.d.mts +77 -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 +26 -20
- 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/codecs/validation.ts +7 -6
- package/src/exports/index.ts +20 -9
- package/src/lower-sql-plan.ts +9 -9
- package/src/middleware/budgets.ts +256 -0
- package/src/middleware/lints.ts +192 -0
- package/src/middleware/sql-middleware.ts +26 -0
- package/src/sql-context.ts +357 -257
- package/src/sql-family-adapter.ts +17 -23
- package/src/sql-marker.ts +2 -2
- package/src/sql-runtime.ts +136 -61
- package/test/async-iterable-result.test.ts +42 -37
- package/test/budgets.test.ts +431 -0
- package/test/context.types.test-d.ts +18 -20
- package/test/execution-stack.test.ts +164 -0
- package/test/json-schema-validation.test.ts +571 -0
- package/test/lints.test.ts +159 -0
- package/test/mutation-default-generators.test.ts +254 -0
- package/test/parameterized-types.test.ts +181 -205
- package/test/sql-context.test.ts +301 -134
- package/test/sql-family-adapter.test.ts +37 -20
- package/test/sql-runtime.test.ts +261 -49
- package/test/utils.ts +101 -67
- 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-APA6GHYY.js +0 -537
- package/dist/chunk-APA6GHYY.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 -130
- 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 -60
- package/dist/test/utils.d.ts.map +0 -1
- package/dist/test/utils.js +0 -24635
- 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-runtime.test.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import type { Contract, ExecutionPlan } from '@prisma-next/contract/types';
|
|
2
|
+
import { coreHash, profileHash } from '@prisma-next/contract/types';
|
|
3
|
+
import {
|
|
4
|
+
type ExecutionStackInstance,
|
|
5
|
+
instantiateExecutionStack,
|
|
6
|
+
type RuntimeDriverInstance,
|
|
7
|
+
type RuntimeExtensionInstance,
|
|
8
|
+
} from '@prisma-next/framework-components/execution';
|
|
9
|
+
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
3
10
|
import type {
|
|
4
11
|
CodecRegistry,
|
|
5
12
|
SelectAst,
|
|
@@ -8,29 +15,34 @@ import type {
|
|
|
8
15
|
} from '@prisma-next/sql-relational-core/ast';
|
|
9
16
|
import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
|
|
10
17
|
import { describe, expect, it, vi } from 'vitest';
|
|
11
|
-
import type {
|
|
18
|
+
import type {
|
|
19
|
+
SqlRuntimeAdapterDescriptor,
|
|
20
|
+
SqlRuntimeAdapterInstance,
|
|
21
|
+
SqlRuntimeTargetDescriptor,
|
|
22
|
+
} from '../src/sql-context';
|
|
23
|
+
import { createExecutionContext, createSqlExecutionStack } from '../src/sql-context';
|
|
12
24
|
import { createRuntime } from '../src/sql-runtime';
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
const testContract: SqlContract<SqlStorage> = {
|
|
16
|
-
schemaVersion: '1',
|
|
26
|
+
const testContract: Contract<SqlStorage> = {
|
|
17
27
|
targetFamily: 'sql',
|
|
18
28
|
target: 'postgres',
|
|
19
|
-
|
|
29
|
+
profileHash: profileHash('sha256:test'),
|
|
20
30
|
models: {},
|
|
21
|
-
|
|
22
|
-
storage: { tables: {} },
|
|
31
|
+
roots: {},
|
|
32
|
+
storage: { storageHash: coreHash('sha256:test'), tables: {} },
|
|
23
33
|
extensionPacks: {},
|
|
24
34
|
capabilities: {},
|
|
25
35
|
meta: {},
|
|
26
|
-
sources: {},
|
|
27
|
-
mappings: {
|
|
28
|
-
codecTypes: {},
|
|
29
|
-
operationTypes: {},
|
|
30
|
-
},
|
|
31
36
|
};
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
interface DriverExecuteSpies {
|
|
39
|
+
rootExecute: ReturnType<typeof vi.fn>;
|
|
40
|
+
connectionExecute: ReturnType<typeof vi.fn>;
|
|
41
|
+
transactionExecute: ReturnType<typeof vi.fn>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type MockSqlDriver = SqlDriver & { __spies: DriverExecuteSpies };
|
|
45
|
+
|
|
34
46
|
function createStubCodecs(): CodecRegistry {
|
|
35
47
|
const registry = createCodecRegistry();
|
|
36
48
|
registry.register(
|
|
@@ -44,7 +56,6 @@ function createStubCodecs(): CodecRegistry {
|
|
|
44
56
|
return registry;
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
// Create a stub adapter
|
|
48
59
|
function createStubAdapter() {
|
|
49
60
|
const codecs = createStubCodecs();
|
|
50
61
|
return {
|
|
@@ -57,6 +68,12 @@ function createStubAdapter() {
|
|
|
57
68
|
codecs() {
|
|
58
69
|
return codecs;
|
|
59
70
|
},
|
|
71
|
+
readMarkerStatement() {
|
|
72
|
+
return {
|
|
73
|
+
sql: 'select core_hash, profile_hash, contract_json, canonical_version, updated_at, app_tag, meta from prisma_contract.marker where id = $1',
|
|
74
|
+
params: [1],
|
|
75
|
+
};
|
|
76
|
+
},
|
|
60
77
|
},
|
|
61
78
|
lower(ast: SelectAst) {
|
|
62
79
|
return {
|
|
@@ -67,37 +84,139 @@ function createStubAdapter() {
|
|
|
67
84
|
};
|
|
68
85
|
}
|
|
69
86
|
|
|
70
|
-
|
|
71
|
-
function
|
|
72
|
-
const execute = vi.fn().mockImplementation(async function* (_request: SqlExecuteRequest) {
|
|
87
|
+
function createMockDriver(): MockSqlDriver {
|
|
88
|
+
const rootExecute = vi.fn().mockImplementation(async function* (_request: SqlExecuteRequest) {
|
|
73
89
|
yield { id: 1 };
|
|
74
90
|
});
|
|
91
|
+
const connectionExecute = vi.fn().mockImplementation(async function* (
|
|
92
|
+
_request: SqlExecuteRequest,
|
|
93
|
+
) {
|
|
94
|
+
yield { id: 2 };
|
|
95
|
+
});
|
|
96
|
+
const transactionExecute = vi.fn().mockImplementation(async function* (
|
|
97
|
+
_request: SqlExecuteRequest,
|
|
98
|
+
) {
|
|
99
|
+
yield { id: 3 };
|
|
100
|
+
});
|
|
75
101
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
102
|
+
const query = vi.fn().mockResolvedValue({ rows: [], rowCount: 0 });
|
|
103
|
+
|
|
104
|
+
const transaction = {
|
|
105
|
+
execute: transactionExecute,
|
|
106
|
+
query,
|
|
107
|
+
commit: vi.fn().mockResolvedValue(undefined),
|
|
108
|
+
rollback: vi.fn().mockResolvedValue(undefined),
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const connection = {
|
|
112
|
+
execute: connectionExecute,
|
|
113
|
+
query,
|
|
114
|
+
release: vi.fn().mockResolvedValue(undefined),
|
|
115
|
+
beginTransaction: vi.fn().mockResolvedValue(transaction),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const driver: SqlDriver = {
|
|
119
|
+
execute: rootExecute,
|
|
120
|
+
query,
|
|
121
|
+
connect: vi.fn().mockImplementation(async (_binding?: undefined) => undefined),
|
|
122
|
+
acquireConnection: vi.fn().mockResolvedValue(connection),
|
|
80
123
|
close: vi.fn().mockResolvedValue(undefined),
|
|
81
124
|
};
|
|
125
|
+
|
|
126
|
+
return Object.assign(driver, {
|
|
127
|
+
__spies: {
|
|
128
|
+
rootExecute,
|
|
129
|
+
connectionExecute,
|
|
130
|
+
transactionExecute,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
82
133
|
}
|
|
83
134
|
|
|
84
|
-
|
|
85
|
-
|
|
135
|
+
function createTestTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {
|
|
136
|
+
return {
|
|
137
|
+
kind: 'target',
|
|
138
|
+
id: 'postgres',
|
|
139
|
+
version: '0.0.1',
|
|
140
|
+
familyId: 'sql' as const,
|
|
141
|
+
targetId: 'postgres' as const,
|
|
142
|
+
codecs: () => createCodecRegistry(),
|
|
143
|
+
parameterizedCodecs: () => [],
|
|
144
|
+
create() {
|
|
145
|
+
return { familyId: 'sql' as const, targetId: 'postgres' as const };
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function createTestAdapterDescriptor(
|
|
151
|
+
adapter: ReturnType<typeof createStubAdapter>,
|
|
152
|
+
): SqlRuntimeAdapterDescriptor<'postgres'> {
|
|
153
|
+
const codecRegistry = adapter.profile.codecs();
|
|
154
|
+
return {
|
|
155
|
+
kind: 'adapter',
|
|
156
|
+
id: 'test-adapter',
|
|
157
|
+
version: '0.0.1',
|
|
158
|
+
familyId: 'sql' as const,
|
|
159
|
+
targetId: 'postgres' as const,
|
|
160
|
+
codecs: () => codecRegistry,
|
|
161
|
+
parameterizedCodecs: () => [],
|
|
162
|
+
create() {
|
|
163
|
+
return Object.assign(
|
|
164
|
+
{ familyId: 'sql' as const, targetId: 'postgres' as const },
|
|
165
|
+
adapter,
|
|
166
|
+
) as SqlRuntimeAdapterInstance<'postgres'>;
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function createTestSetup() {
|
|
86
172
|
const adapter = createStubAdapter();
|
|
173
|
+
const driver = createMockDriver();
|
|
174
|
+
|
|
175
|
+
const targetDescriptor = createTestTargetDescriptor();
|
|
176
|
+
const adapterDescriptor = createTestAdapterDescriptor(adapter);
|
|
177
|
+
|
|
178
|
+
const stack = createSqlExecutionStack({
|
|
179
|
+
target: targetDescriptor,
|
|
180
|
+
adapter: adapterDescriptor,
|
|
181
|
+
extensionPacks: [],
|
|
182
|
+
});
|
|
183
|
+
type SqlTestStackInstance = ExecutionStackInstance<
|
|
184
|
+
'sql',
|
|
185
|
+
'postgres',
|
|
186
|
+
SqlRuntimeAdapterInstance<'postgres'>,
|
|
187
|
+
RuntimeDriverInstance<'sql', 'postgres'>,
|
|
188
|
+
RuntimeExtensionInstance<'sql', 'postgres'>
|
|
189
|
+
>;
|
|
190
|
+
const stackInstance = instantiateExecutionStack(stack) as SqlTestStackInstance;
|
|
191
|
+
|
|
192
|
+
const context = createExecutionContext({
|
|
193
|
+
contract: testContract,
|
|
194
|
+
stack: { target: targetDescriptor, adapter: adapterDescriptor, extensionPacks: [] },
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
return { stackInstance, context, driver };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function createRawExecutionPlan<Row = Record<string, unknown>>(): ExecutionPlan<Row> {
|
|
87
201
|
return {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
202
|
+
sql: 'select 1',
|
|
203
|
+
params: [],
|
|
204
|
+
meta: {
|
|
205
|
+
target: testContract.target,
|
|
206
|
+
targetFamily: testContract.targetFamily,
|
|
207
|
+
storageHash: testContract.storage.storageHash,
|
|
208
|
+
lane: 'raw',
|
|
209
|
+
paramDescriptors: [],
|
|
210
|
+
},
|
|
92
211
|
};
|
|
93
212
|
}
|
|
94
213
|
|
|
95
214
|
describe('createRuntime', () => {
|
|
96
|
-
it('creates runtime with
|
|
97
|
-
const context =
|
|
98
|
-
const driver = createMockDriver();
|
|
215
|
+
it('creates runtime with context and driver', () => {
|
|
216
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
99
217
|
|
|
100
218
|
const runtime = createRuntime({
|
|
219
|
+
stackInstance,
|
|
101
220
|
context,
|
|
102
221
|
driver,
|
|
103
222
|
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
@@ -106,50 +225,143 @@ describe('createRuntime', () => {
|
|
|
106
225
|
expect(runtime).toBeDefined();
|
|
107
226
|
expect(runtime.execute).toBeDefined();
|
|
108
227
|
expect(runtime.telemetry).toBeDefined();
|
|
109
|
-
expect(runtime.operations).toBeDefined();
|
|
110
228
|
expect(runtime.close).toBeDefined();
|
|
111
229
|
});
|
|
112
230
|
|
|
113
|
-
it('returns
|
|
114
|
-
const context =
|
|
115
|
-
|
|
231
|
+
it('returns null telemetry when no events', () => {
|
|
232
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
233
|
+
|
|
234
|
+
const runtime = createRuntime({
|
|
235
|
+
stackInstance,
|
|
236
|
+
context,
|
|
237
|
+
driver,
|
|
238
|
+
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(runtime.telemetry()).toBeNull();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('closes runtime and driver', async () => {
|
|
245
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
116
246
|
|
|
117
247
|
const runtime = createRuntime({
|
|
248
|
+
stackInstance,
|
|
118
249
|
context,
|
|
119
250
|
driver,
|
|
120
251
|
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
121
252
|
});
|
|
122
253
|
|
|
123
|
-
|
|
124
|
-
expect(
|
|
125
|
-
expect(ops.byType).toBeDefined();
|
|
254
|
+
await runtime.close();
|
|
255
|
+
expect(driver.close).toHaveBeenCalled();
|
|
126
256
|
});
|
|
127
257
|
|
|
128
|
-
it('
|
|
129
|
-
const context =
|
|
130
|
-
|
|
258
|
+
it('validates codec registry at startup when verify mode is startup', () => {
|
|
259
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
260
|
+
|
|
261
|
+
const runtime = createRuntime({
|
|
262
|
+
stackInstance,
|
|
263
|
+
context,
|
|
264
|
+
driver,
|
|
265
|
+
verify: { mode: 'startup', requireMarker: false },
|
|
266
|
+
});
|
|
131
267
|
|
|
268
|
+
expect(runtime).toBeDefined();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('uses acquired connection queryable for connection.execute', async () => {
|
|
272
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
132
273
|
const runtime = createRuntime({
|
|
274
|
+
stackInstance,
|
|
133
275
|
context,
|
|
134
276
|
driver,
|
|
135
277
|
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
136
278
|
});
|
|
137
279
|
|
|
138
|
-
|
|
139
|
-
|
|
280
|
+
const connection = await runtime.connection();
|
|
281
|
+
await connection.execute(createRawExecutionPlan()).toArray();
|
|
282
|
+
|
|
283
|
+
expect(driver.__spies.connectionExecute).toHaveBeenCalledTimes(1);
|
|
284
|
+
expect(driver.__spies.transactionExecute).not.toHaveBeenCalled();
|
|
285
|
+
expect(driver.__spies.rootExecute).not.toHaveBeenCalled();
|
|
286
|
+
|
|
287
|
+
await connection.release();
|
|
140
288
|
});
|
|
141
289
|
|
|
142
|
-
it('
|
|
143
|
-
const context =
|
|
144
|
-
const
|
|
290
|
+
it('uses transaction queryable for transaction.execute', async () => {
|
|
291
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
292
|
+
const runtime = createRuntime({
|
|
293
|
+
stackInstance,
|
|
294
|
+
context,
|
|
295
|
+
driver,
|
|
296
|
+
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
const connection = await runtime.connection();
|
|
300
|
+
const transaction = await connection.transaction();
|
|
301
|
+
await transaction.execute(createRawExecutionPlan()).toArray();
|
|
302
|
+
|
|
303
|
+
expect(driver.__spies.transactionExecute).toHaveBeenCalledTimes(1);
|
|
304
|
+
expect(driver.__spies.connectionExecute).not.toHaveBeenCalled();
|
|
305
|
+
expect(driver.__spies.rootExecute).not.toHaveBeenCalled();
|
|
306
|
+
|
|
307
|
+
await transaction.rollback();
|
|
308
|
+
await connection.release();
|
|
309
|
+
});
|
|
145
310
|
|
|
311
|
+
it('keeps root execute on driver queryable for runtime.execute', async () => {
|
|
312
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
146
313
|
const runtime = createRuntime({
|
|
314
|
+
stackInstance,
|
|
147
315
|
context,
|
|
148
316
|
driver,
|
|
149
317
|
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
150
318
|
});
|
|
151
319
|
|
|
152
|
-
await runtime.
|
|
153
|
-
|
|
320
|
+
await runtime.execute(createRawExecutionPlan()).toArray();
|
|
321
|
+
|
|
322
|
+
expect(driver.__spies.rootExecute).toHaveBeenCalledTimes(1);
|
|
323
|
+
expect(driver.__spies.connectionExecute).not.toHaveBeenCalled();
|
|
324
|
+
expect(driver.__spies.transactionExecute).not.toHaveBeenCalled();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('accepts a generic middleware (no familyId)', () => {
|
|
328
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
329
|
+
expect(() =>
|
|
330
|
+
createRuntime({
|
|
331
|
+
stackInstance,
|
|
332
|
+
context,
|
|
333
|
+
driver,
|
|
334
|
+
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
335
|
+
middleware: [{ name: 'generic' }],
|
|
336
|
+
}),
|
|
337
|
+
).not.toThrow();
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('accepts an SQL middleware', () => {
|
|
341
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
342
|
+
expect(() =>
|
|
343
|
+
createRuntime({
|
|
344
|
+
stackInstance,
|
|
345
|
+
context,
|
|
346
|
+
driver,
|
|
347
|
+
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
348
|
+
middleware: [{ name: 'sql-lints', familyId: 'sql' }],
|
|
349
|
+
}),
|
|
350
|
+
).not.toThrow();
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('rejects a Mongo middleware with a clear error', () => {
|
|
354
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
355
|
+
expect(() =>
|
|
356
|
+
createRuntime({
|
|
357
|
+
stackInstance,
|
|
358
|
+
context,
|
|
359
|
+
driver,
|
|
360
|
+
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
361
|
+
middleware: [{ name: 'mongo-mw', familyId: 'mongo' }],
|
|
362
|
+
}),
|
|
363
|
+
).toThrow(
|
|
364
|
+
"Middleware 'mongo-mw' requires family 'mongo' but the runtime is configured for family 'sql'",
|
|
365
|
+
);
|
|
154
366
|
});
|
|
155
367
|
});
|
package/test/utils.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import type { ExecutionPlan, ResultType } from '@prisma-next/contract/types';
|
|
2
|
-
import
|
|
1
|
+
import type { Contract, ExecutionPlan, ResultType } from '@prisma-next/contract/types';
|
|
2
|
+
import { coreHash, profileHash } from '@prisma-next/contract/types';
|
|
3
|
+
import {
|
|
4
|
+
instantiateExecutionStack,
|
|
5
|
+
type RuntimeDriverDescriptor,
|
|
6
|
+
} from '@prisma-next/framework-components/execution';
|
|
7
|
+
import { builtinGeneratorIds } from '@prisma-next/ids';
|
|
8
|
+
import { generateId } from '@prisma-next/ids/runtime';
|
|
9
|
+
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
3
10
|
import type { Adapter, LoweredStatement, SelectAst } from '@prisma-next/sql-relational-core/ast';
|
|
4
11
|
import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
|
|
5
12
|
import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
|
|
@@ -7,18 +14,29 @@ import { collectAsync, drainAsyncIterable } from '@prisma-next/test-utils';
|
|
|
7
14
|
import type { Client } from 'pg';
|
|
8
15
|
import type { SqlStatement } from '../src/exports';
|
|
9
16
|
import {
|
|
17
|
+
createExecutionContext,
|
|
10
18
|
type createRuntime,
|
|
11
|
-
|
|
19
|
+
createSqlExecutionStack,
|
|
12
20
|
ensureSchemaStatement,
|
|
13
21
|
ensureTableStatement,
|
|
14
22
|
writeContractMarker,
|
|
15
23
|
} from '../src/exports';
|
|
16
24
|
import type {
|
|
17
|
-
|
|
25
|
+
ExecutionContext,
|
|
26
|
+
SqlRuntimeAdapterDescriptor,
|
|
18
27
|
SqlRuntimeAdapterInstance,
|
|
28
|
+
SqlRuntimeDriverInstance,
|
|
19
29
|
SqlRuntimeExtensionDescriptor,
|
|
30
|
+
SqlRuntimeTargetDescriptor,
|
|
20
31
|
} from '../src/sql-context';
|
|
21
32
|
|
|
33
|
+
function createTestMutationDefaultGenerators() {
|
|
34
|
+
return builtinGeneratorIds.map((id) => ({
|
|
35
|
+
id,
|
|
36
|
+
generate: (params?: Record<string, unknown>) => generateId(params ? { id, params } : { id }),
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
|
|
22
40
|
/**
|
|
23
41
|
* Executes a plan and collects all results into an array.
|
|
24
42
|
* This helper DRYs up the common pattern of executing plans in tests.
|
|
@@ -60,7 +78,7 @@ export async function executeStatement(client: Client, statement: SqlStatement):
|
|
|
60
78
|
*/
|
|
61
79
|
export async function setupTestDatabase(
|
|
62
80
|
client: Client,
|
|
63
|
-
contract:
|
|
81
|
+
contract: Contract<SqlStorage>,
|
|
64
82
|
setupFn: (client: Client) => Promise<void>,
|
|
65
83
|
): Promise<void> {
|
|
66
84
|
await client.query('drop schema if exists prisma_contract cascade');
|
|
@@ -71,8 +89,8 @@ export async function setupTestDatabase(
|
|
|
71
89
|
await executeStatement(client, ensureSchemaStatement);
|
|
72
90
|
await executeStatement(client, ensureTableStatement);
|
|
73
91
|
const write = writeContractMarker({
|
|
74
|
-
|
|
75
|
-
profileHash: contract.profileHash
|
|
92
|
+
storageHash: contract.storage.storageHash,
|
|
93
|
+
profileHash: contract.profileHash,
|
|
76
94
|
contractJson: contract,
|
|
77
95
|
canonicalVersion: 1,
|
|
78
96
|
});
|
|
@@ -85,11 +103,11 @@ export async function setupTestDatabase(
|
|
|
85
103
|
*/
|
|
86
104
|
export async function writeTestContractMarker(
|
|
87
105
|
client: Client,
|
|
88
|
-
contract:
|
|
106
|
+
contract: Contract<SqlStorage>,
|
|
89
107
|
): Promise<void> {
|
|
90
108
|
const write = writeContractMarker({
|
|
91
|
-
|
|
92
|
-
profileHash: contract.profileHash
|
|
109
|
+
storageHash: contract.storage.storageHash,
|
|
110
|
+
profileHash: contract.profileHash,
|
|
93
111
|
contractJson: contract,
|
|
94
112
|
canonicalVersion: 1,
|
|
95
113
|
});
|
|
@@ -98,56 +116,40 @@ export async function writeTestContractMarker(
|
|
|
98
116
|
|
|
99
117
|
/**
|
|
100
118
|
* Creates a test adapter descriptor from a raw adapter.
|
|
101
|
-
*
|
|
102
|
-
*
|
|
119
|
+
* Wraps the adapter in an SqlRuntimeAdapterDescriptor with static contributions
|
|
120
|
+
* derived from the adapter's codec registry.
|
|
103
121
|
*/
|
|
104
|
-
function createTestAdapterDescriptor(
|
|
105
|
-
adapter: Adapter<SelectAst,
|
|
106
|
-
): {
|
|
107
|
-
|
|
108
|
-
readonly id: string;
|
|
109
|
-
readonly version: string;
|
|
110
|
-
readonly familyId: 'sql';
|
|
111
|
-
readonly targetId: 'postgres';
|
|
112
|
-
create(): SqlRuntimeAdapterInstance<'postgres'>;
|
|
113
|
-
} {
|
|
122
|
+
export function createTestAdapterDescriptor(
|
|
123
|
+
adapter: Adapter<SelectAst, Contract<SqlStorage>, LoweredStatement>,
|
|
124
|
+
): SqlRuntimeAdapterDescriptor<'postgres'> {
|
|
125
|
+
const codecRegistry = adapter.profile.codecs();
|
|
114
126
|
return {
|
|
115
127
|
kind: 'adapter' as const,
|
|
116
128
|
id: 'test-adapter',
|
|
117
129
|
version: '0.0.1',
|
|
118
130
|
familyId: 'sql' as const,
|
|
119
131
|
targetId: 'postgres' as const,
|
|
132
|
+
codecs: () => codecRegistry,
|
|
133
|
+
parameterizedCodecs: () => [],
|
|
134
|
+
mutationDefaultGenerators: createTestMutationDefaultGenerators,
|
|
120
135
|
create(): SqlRuntimeAdapterInstance<'postgres'> {
|
|
121
|
-
|
|
122
|
-
return Object.assign(
|
|
123
|
-
{
|
|
124
|
-
familyId: 'sql' as const,
|
|
125
|
-
targetId: 'postgres' as const,
|
|
126
|
-
},
|
|
127
|
-
adapter,
|
|
128
|
-
);
|
|
136
|
+
return Object.assign({ familyId: 'sql' as const, targetId: 'postgres' as const }, adapter);
|
|
129
137
|
},
|
|
130
138
|
};
|
|
131
139
|
}
|
|
132
140
|
|
|
133
141
|
/**
|
|
134
|
-
* Creates a test target descriptor.
|
|
135
|
-
* This is a minimal descriptor for descriptor-first context creation in tests.
|
|
142
|
+
* Creates a test target descriptor with empty static contributions.
|
|
136
143
|
*/
|
|
137
|
-
function createTestTargetDescriptor(): {
|
|
138
|
-
readonly kind: 'target';
|
|
139
|
-
readonly id: string;
|
|
140
|
-
readonly version: string;
|
|
141
|
-
readonly familyId: 'sql';
|
|
142
|
-
readonly targetId: 'postgres';
|
|
143
|
-
create(): { readonly familyId: 'sql'; readonly targetId: 'postgres' };
|
|
144
|
-
} {
|
|
144
|
+
export function createTestTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {
|
|
145
145
|
return {
|
|
146
146
|
kind: 'target' as const,
|
|
147
147
|
id: 'postgres',
|
|
148
148
|
version: '0.0.1',
|
|
149
149
|
familyId: 'sql' as const,
|
|
150
150
|
targetId: 'postgres' as const,
|
|
151
|
+
codecs: () => createCodecRegistry(),
|
|
152
|
+
parameterizedCodecs: () => [],
|
|
151
153
|
create() {
|
|
152
154
|
return { familyId: 'sql' as const, targetId: 'postgres' as const };
|
|
153
155
|
},
|
|
@@ -155,25 +157,46 @@ function createTestTargetDescriptor(): {
|
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
/**
|
|
158
|
-
* Creates
|
|
160
|
+
* Creates an ExecutionContext for testing.
|
|
159
161
|
* This helper DRYs up the common pattern of context creation in tests.
|
|
160
162
|
*
|
|
161
163
|
* Accepts a raw adapter and optional extension descriptors, wrapping the
|
|
162
164
|
* adapter in a descriptor internally for descriptor-first context creation.
|
|
163
165
|
*/
|
|
164
|
-
export function createTestContext<TContract extends
|
|
166
|
+
export function createTestContext<TContract extends Contract<SqlStorage>>(
|
|
165
167
|
contract: TContract,
|
|
166
|
-
adapter: Adapter<SelectAst,
|
|
168
|
+
adapter: Adapter<SelectAst, Contract<SqlStorage>, LoweredStatement>,
|
|
167
169
|
options?: {
|
|
168
170
|
extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;
|
|
169
171
|
},
|
|
170
|
-
):
|
|
171
|
-
return
|
|
172
|
+
): ExecutionContext<TContract> {
|
|
173
|
+
return createExecutionContext({
|
|
172
174
|
contract,
|
|
175
|
+
stack: {
|
|
176
|
+
target: createTestTargetDescriptor(),
|
|
177
|
+
adapter: createTestAdapterDescriptor(adapter),
|
|
178
|
+
extensionPacks: options?.extensionPacks ?? [],
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function createTestStackInstance(options?: {
|
|
184
|
+
extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<'postgres'>>;
|
|
185
|
+
driver?: RuntimeDriverDescriptor<
|
|
186
|
+
'sql',
|
|
187
|
+
'postgres',
|
|
188
|
+
unknown,
|
|
189
|
+
SqlRuntimeDriverInstance<'postgres'>
|
|
190
|
+
>;
|
|
191
|
+
}) {
|
|
192
|
+
const stack = createSqlExecutionStack({
|
|
173
193
|
target: createTestTargetDescriptor(),
|
|
174
|
-
adapter: createTestAdapterDescriptor(
|
|
194
|
+
adapter: createTestAdapterDescriptor(createStubAdapter()),
|
|
195
|
+
driver: options?.driver,
|
|
175
196
|
extensionPacks: options?.extensionPacks ?? [],
|
|
176
197
|
});
|
|
198
|
+
|
|
199
|
+
return instantiateExecutionStack(stack);
|
|
177
200
|
}
|
|
178
201
|
|
|
179
202
|
/**
|
|
@@ -183,7 +206,7 @@ export function createTestContext<TContract extends SqlContract<SqlStorage>>(
|
|
|
183
206
|
* The stub adapter includes simple codecs for common test types (pg/int4@1, pg/text@1, pg/timestamptz@1)
|
|
184
207
|
* to enable type inference in tests without requiring the postgres adapter package.
|
|
185
208
|
*/
|
|
186
|
-
export function createStubAdapter(): Adapter<SelectAst,
|
|
209
|
+
export function createStubAdapter(): Adapter<SelectAst, Contract<SqlStorage>, LoweredStatement> {
|
|
187
210
|
const codecRegistry = createCodecRegistry();
|
|
188
211
|
|
|
189
212
|
// Register stub codecs for common test types
|
|
@@ -212,8 +235,7 @@ export function createStubAdapter(): Adapter<SelectAst, SqlContract<SqlStorage>,
|
|
|
212
235
|
typeId: 'pg/timestamptz@1',
|
|
213
236
|
targetTypes: ['timestamptz'],
|
|
214
237
|
encode: (value: string | Date) => (value instanceof Date ? value.toISOString() : value),
|
|
215
|
-
decode: (wire: string | Date) =>
|
|
216
|
-
typeof wire === 'string' ? wire : wire instanceof Date ? wire.toISOString() : String(wire),
|
|
238
|
+
decode: (wire: string | Date) => (wire instanceof Date ? wire : new Date(wire)),
|
|
217
239
|
}),
|
|
218
240
|
);
|
|
219
241
|
|
|
@@ -225,8 +247,14 @@ export function createStubAdapter(): Adapter<SelectAst, SqlContract<SqlStorage>,
|
|
|
225
247
|
codecs() {
|
|
226
248
|
return codecRegistry;
|
|
227
249
|
},
|
|
250
|
+
readMarkerStatement() {
|
|
251
|
+
return {
|
|
252
|
+
sql: 'select core_hash, profile_hash, contract_json, canonical_version, updated_at, app_tag, meta from prisma_contract.marker where id = $1',
|
|
253
|
+
params: [1],
|
|
254
|
+
};
|
|
255
|
+
},
|
|
228
256
|
},
|
|
229
|
-
lower(ast: SelectAst, ctx: { contract:
|
|
257
|
+
lower(ast: SelectAst, ctx: { contract: Contract<SqlStorage>; params?: readonly unknown[] }) {
|
|
230
258
|
const sqlText = JSON.stringify(ast);
|
|
231
259
|
return {
|
|
232
260
|
profileId: this.profile.id,
|
|
@@ -236,24 +264,30 @@ export function createStubAdapter(): Adapter<SelectAst, SqlContract<SqlStorage>,
|
|
|
236
264
|
};
|
|
237
265
|
}
|
|
238
266
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
267
|
+
export function createTestContract(
|
|
268
|
+
contract: Partial<Omit<Contract<SqlStorage>, 'profileHash' | 'storage'>> & {
|
|
269
|
+
storageHash?: string;
|
|
270
|
+
profileHash?: string;
|
|
271
|
+
storage?: Omit<SqlStorage, 'storageHash'>;
|
|
272
|
+
},
|
|
273
|
+
): Contract<SqlStorage> {
|
|
274
|
+
const { execution, ...rest } = contract;
|
|
275
|
+
const storageHashValue = coreHash(rest['storageHash'] ?? 'sha256:testcore');
|
|
276
|
+
|
|
249
277
|
return {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
278
|
+
target: rest['target'] ?? 'postgres',
|
|
279
|
+
targetFamily: rest['targetFamily'] ?? 'sql',
|
|
280
|
+
storage: rest['storage']
|
|
281
|
+
? { ...rest['storage'], storageHash: storageHashValue }
|
|
282
|
+
: { storageHash: storageHashValue, tables: {} },
|
|
283
|
+
models: rest['models'] ?? {},
|
|
284
|
+
roots: rest['roots'] ?? {},
|
|
285
|
+
capabilities: rest['capabilities'] ?? {},
|
|
286
|
+
extensionPacks: rest['extensionPacks'] ?? {},
|
|
287
|
+
meta: rest['meta'] ?? {},
|
|
288
|
+
...(execution ? { execution } : {}),
|
|
289
|
+
profileHash: profileHash(rest['profileHash'] ?? 'sha256:testprofile'),
|
|
290
|
+
};
|
|
257
291
|
}
|
|
258
292
|
|
|
259
293
|
// Re-export generic utilities from test-utils
|