@prisma-next/sql-runtime 0.3.0-dev.13 → 0.3.0-dev.146
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-DGa0ipuP.mjs +956 -0
- package/dist/exports-DGa0ipuP.mjs.map +1 -0
- package/dist/index-CDbmlDcn.d.mts +177 -0
- package/dist/index-CDbmlDcn.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 +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/codecs/validation.ts +6 -5
- package/src/exports/index.ts +19 -7
- package/src/lower-sql-plan.ts +9 -9
- package/src/plugins/budgets.ts +375 -0
- package/src/plugins/lints.ts +211 -0
- package/src/sql-context.ts +454 -108
- package/src/sql-family-adapter.ts +16 -22
- package/src/sql-marker.ts +2 -2
- package/src/sql-runtime.ts +136 -47
- package/test/async-iterable-result.test.ts +42 -37
- package/test/budgets.test.ts +481 -0
- package/test/context.types.test-d.ts +68 -0
- package/test/execution-stack.test.ts +164 -0
- package/test/json-schema-validation.test.ts +571 -0
- package/test/lints.test.ts +161 -0
- package/test/mutation-default-generators.test.ts +254 -0
- package/test/parameterized-types.test.ts +529 -0
- package/test/sql-context.test.ts +301 -134
- package/test/sql-family-adapter.test.ts +37 -20
- package/test/sql-runtime.test.ts +220 -49
- package/test/utils.ts +102 -64
- 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-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
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
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
|
+
};
|
|
82
148
|
}
|
|
83
149
|
|
|
84
|
-
|
|
85
|
-
|
|
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,102 @@ 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
|
-
const driver = createMockDriver();
|
|
231
|
+
it('returns null telemetry when no events', () => {
|
|
232
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
116
233
|
|
|
117
234
|
const runtime = createRuntime({
|
|
235
|
+
stackInstance,
|
|
118
236
|
context,
|
|
119
237
|
driver,
|
|
120
238
|
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
121
239
|
});
|
|
122
240
|
|
|
123
|
-
|
|
124
|
-
expect(ops).toBeDefined();
|
|
125
|
-
expect(ops.byType).toBeDefined();
|
|
241
|
+
expect(runtime.telemetry()).toBeNull();
|
|
126
242
|
});
|
|
127
243
|
|
|
128
|
-
it('
|
|
129
|
-
const context =
|
|
130
|
-
const driver = createMockDriver();
|
|
244
|
+
it('closes runtime and driver', async () => {
|
|
245
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
131
246
|
|
|
132
247
|
const runtime = createRuntime({
|
|
248
|
+
stackInstance,
|
|
133
249
|
context,
|
|
134
250
|
driver,
|
|
135
251
|
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
136
252
|
});
|
|
137
253
|
|
|
138
|
-
|
|
139
|
-
expect(
|
|
254
|
+
await runtime.close();
|
|
255
|
+
expect(driver.close).toHaveBeenCalled();
|
|
140
256
|
});
|
|
141
257
|
|
|
142
|
-
it('
|
|
143
|
-
const context =
|
|
144
|
-
const driver = createMockDriver();
|
|
258
|
+
it('validates codec registry at startup when verify mode is startup', () => {
|
|
259
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
145
260
|
|
|
146
261
|
const runtime = createRuntime({
|
|
262
|
+
stackInstance,
|
|
263
|
+
context,
|
|
264
|
+
driver,
|
|
265
|
+
verify: { mode: 'startup', requireMarker: false },
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
expect(runtime).toBeDefined();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('uses acquired connection queryable for connection.execute', async () => {
|
|
272
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
273
|
+
const runtime = createRuntime({
|
|
274
|
+
stackInstance,
|
|
147
275
|
context,
|
|
148
276
|
driver,
|
|
149
277
|
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
150
278
|
});
|
|
151
279
|
|
|
152
|
-
await runtime.
|
|
153
|
-
|
|
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();
|
|
288
|
+
});
|
|
289
|
+
|
|
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
|
+
});
|
|
310
|
+
|
|
311
|
+
it('keeps root execute on driver queryable for runtime.execute', async () => {
|
|
312
|
+
const { stackInstance, context, driver } = createTestSetup();
|
|
313
|
+
const runtime = createRuntime({
|
|
314
|
+
stackInstance,
|
|
315
|
+
context,
|
|
316
|
+
driver,
|
|
317
|
+
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
318
|
+
});
|
|
319
|
+
|
|
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();
|
|
154
325
|
});
|
|
155
326
|
});
|
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,20 +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
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
+
|
|
277
|
+
return {
|
|
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
|
+
};
|
|
253
291
|
}
|
|
254
292
|
|
|
255
293
|
// Re-export generic utilities from test-utils
|