@prisma-next/sql-runtime 0.3.0-dev.4 → 0.3.0-dev.41
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/README.md +116 -26
- package/dist/exports-C8hi0N-a.mjs +622 -0
- package/dist/exports-C8hi0N-a.mjs.map +1 -0
- package/dist/index-SlQIrV_t.d.mts +131 -0
- package/dist/index-SlQIrV_t.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 +35 -26
- package/src/codecs/decoding.ts +221 -0
- package/src/codecs/encoding.ts +89 -0
- package/src/codecs/json-schema-validation.ts +61 -0
- package/src/codecs/validation.ts +67 -0
- package/src/exports/index.ts +45 -0
- package/src/lower-sql-plan.ts +32 -0
- package/src/sql-context.ts +443 -0
- package/src/sql-family-adapter.ts +47 -0
- package/src/sql-marker.ts +105 -0
- package/src/sql-runtime.ts +232 -0
- package/test/async-iterable-result.test.ts +144 -0
- package/test/context.types.test-d.ts +68 -0
- package/test/execution-stack.test.ts +166 -0
- package/test/json-schema-validation.test.ts +653 -0
- package/test/parameterized-types.test.ts +539 -0
- package/test/sql-context.test.ts +392 -0
- package/test/sql-family-adapter.test.ts +87 -0
- package/test/sql-runtime.test.ts +241 -0
- package/test/utils.ts +291 -0
- 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.d.ts +0 -29
- 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/sql-runtime-DgEbg2OP.d.ts +0 -109
- 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 -64
- 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
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import type { ExecutionPlan } from '@prisma-next/contract/types';
|
|
2
|
+
import type { ExecutionStackInstance } from '@prisma-next/core-execution-plane/stack';
|
|
3
|
+
import type { RuntimeDriverInstance } from '@prisma-next/core-execution-plane/types';
|
|
4
|
+
import type { OperationRegistry } from '@prisma-next/operations';
|
|
5
|
+
import type {
|
|
6
|
+
Log,
|
|
7
|
+
Plugin,
|
|
8
|
+
RuntimeCore,
|
|
9
|
+
RuntimeCoreOptions,
|
|
10
|
+
RuntimeTelemetryEvent,
|
|
11
|
+
RuntimeVerifyOptions,
|
|
12
|
+
TelemetryOutcome,
|
|
13
|
+
} from '@prisma-next/runtime-executor';
|
|
14
|
+
import { AsyncIterableResult, createRuntimeCore } from '@prisma-next/runtime-executor';
|
|
15
|
+
import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
16
|
+
import type {
|
|
17
|
+
Adapter,
|
|
18
|
+
CodecRegistry,
|
|
19
|
+
LoweredStatement,
|
|
20
|
+
QueryAst,
|
|
21
|
+
SelectAst,
|
|
22
|
+
SqlDriver,
|
|
23
|
+
} from '@prisma-next/sql-relational-core/ast';
|
|
24
|
+
import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
|
|
25
|
+
import type { JsonSchemaValidatorRegistry } from '@prisma-next/sql-relational-core/query-lane-context';
|
|
26
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
27
|
+
import { decodeRow } from './codecs/decoding';
|
|
28
|
+
import { encodeParams } from './codecs/encoding';
|
|
29
|
+
import { validateCodecRegistryCompleteness } from './codecs/validation';
|
|
30
|
+
import { lowerSqlPlan } from './lower-sql-plan';
|
|
31
|
+
import type {
|
|
32
|
+
ExecutionContext,
|
|
33
|
+
SqlRuntimeAdapterInstance,
|
|
34
|
+
SqlRuntimeExtensionInstance,
|
|
35
|
+
} from './sql-context';
|
|
36
|
+
import { SqlFamilyAdapter } from './sql-family-adapter';
|
|
37
|
+
|
|
38
|
+
export interface RuntimeOptions<
|
|
39
|
+
TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
|
|
40
|
+
> {
|
|
41
|
+
readonly context: ExecutionContext<TContract>;
|
|
42
|
+
readonly adapter: Adapter<QueryAst, SqlContract<SqlStorage>, LoweredStatement>;
|
|
43
|
+
readonly driver: SqlDriver<unknown>;
|
|
44
|
+
readonly verify: RuntimeVerifyOptions;
|
|
45
|
+
readonly plugins?: readonly Plugin<
|
|
46
|
+
TContract,
|
|
47
|
+
Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
|
|
48
|
+
SqlDriver<unknown>
|
|
49
|
+
>[];
|
|
50
|
+
readonly mode?: 'strict' | 'permissive';
|
|
51
|
+
readonly log?: Log;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface CreateRuntimeOptions<
|
|
55
|
+
TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
|
|
56
|
+
TTargetId extends string = string,
|
|
57
|
+
> {
|
|
58
|
+
readonly stackInstance: ExecutionStackInstance<
|
|
59
|
+
'sql',
|
|
60
|
+
TTargetId,
|
|
61
|
+
SqlRuntimeAdapterInstance<TTargetId>,
|
|
62
|
+
RuntimeDriverInstance<'sql', TTargetId>,
|
|
63
|
+
SqlRuntimeExtensionInstance<TTargetId>
|
|
64
|
+
>;
|
|
65
|
+
readonly context: ExecutionContext<TContract>;
|
|
66
|
+
readonly driver: SqlDriver<unknown>;
|
|
67
|
+
readonly verify: RuntimeVerifyOptions;
|
|
68
|
+
readonly plugins?: readonly Plugin<
|
|
69
|
+
TContract,
|
|
70
|
+
Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
|
|
71
|
+
SqlDriver<unknown>
|
|
72
|
+
>[];
|
|
73
|
+
readonly mode?: 'strict' | 'permissive';
|
|
74
|
+
readonly log?: Log;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface Runtime extends RuntimeQueryable {
|
|
78
|
+
connection(): Promise<RuntimeConnection>;
|
|
79
|
+
telemetry(): RuntimeTelemetryEvent | null;
|
|
80
|
+
close(): Promise<void>;
|
|
81
|
+
operations(): OperationRegistry;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface RuntimeConnection extends RuntimeQueryable {
|
|
85
|
+
transaction(): Promise<RuntimeTransaction>;
|
|
86
|
+
release(): Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface RuntimeTransaction extends RuntimeQueryable {
|
|
90
|
+
commit(): Promise<void>;
|
|
91
|
+
rollback(): Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface RuntimeQueryable {
|
|
95
|
+
execute<Row = Record<string, unknown>>(
|
|
96
|
+
plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
|
|
97
|
+
): AsyncIterableResult<Row>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type { RuntimeTelemetryEvent, RuntimeVerifyOptions, TelemetryOutcome };
|
|
101
|
+
|
|
102
|
+
class SqlRuntimeImpl<TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>>
|
|
103
|
+
implements Runtime
|
|
104
|
+
{
|
|
105
|
+
private readonly core: RuntimeCore<
|
|
106
|
+
TContract,
|
|
107
|
+
Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
|
|
108
|
+
SqlDriver<unknown>
|
|
109
|
+
>;
|
|
110
|
+
private readonly contract: TContract;
|
|
111
|
+
private readonly adapter: Adapter<QueryAst, SqlContract<SqlStorage>, LoweredStatement>;
|
|
112
|
+
private readonly codecRegistry: CodecRegistry;
|
|
113
|
+
private readonly jsonSchemaValidators: JsonSchemaValidatorRegistry | undefined;
|
|
114
|
+
private codecRegistryValidated: boolean;
|
|
115
|
+
|
|
116
|
+
constructor(options: RuntimeOptions<TContract>) {
|
|
117
|
+
const { context, adapter, driver, verify, plugins, mode, log } = options;
|
|
118
|
+
this.contract = context.contract;
|
|
119
|
+
this.adapter = adapter;
|
|
120
|
+
this.codecRegistry = context.codecs;
|
|
121
|
+
this.jsonSchemaValidators = context.jsonSchemaValidators;
|
|
122
|
+
this.codecRegistryValidated = false;
|
|
123
|
+
|
|
124
|
+
const familyAdapter = new SqlFamilyAdapter(context.contract);
|
|
125
|
+
|
|
126
|
+
const coreOptions: RuntimeCoreOptions<
|
|
127
|
+
TContract,
|
|
128
|
+
Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
|
|
129
|
+
SqlDriver<unknown>
|
|
130
|
+
> = {
|
|
131
|
+
familyAdapter,
|
|
132
|
+
driver,
|
|
133
|
+
verify,
|
|
134
|
+
plugins: plugins as readonly Plugin<
|
|
135
|
+
TContract,
|
|
136
|
+
Adapter<SelectAst, SqlContract<SqlStorage>, LoweredStatement>,
|
|
137
|
+
SqlDriver<unknown>
|
|
138
|
+
>[],
|
|
139
|
+
...ifDefined('mode', mode),
|
|
140
|
+
...ifDefined('log', log),
|
|
141
|
+
operationRegistry: context.operations,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
this.core = createRuntimeCore(coreOptions);
|
|
145
|
+
|
|
146
|
+
if (verify.mode === 'startup') {
|
|
147
|
+
validateCodecRegistryCompleteness(this.codecRegistry, context.contract);
|
|
148
|
+
this.codecRegistryValidated = true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private ensureCodecRegistryValidated(contract: SqlContract<SqlStorage>): void {
|
|
153
|
+
if (!this.codecRegistryValidated) {
|
|
154
|
+
validateCodecRegistryCompleteness(this.codecRegistry, contract);
|
|
155
|
+
this.codecRegistryValidated = true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
execute<Row = Record<string, unknown>>(
|
|
160
|
+
plan: ExecutionPlan<Row> | SqlQueryPlan<Row>,
|
|
161
|
+
): AsyncIterableResult<Row> {
|
|
162
|
+
this.ensureCodecRegistryValidated(this.contract);
|
|
163
|
+
|
|
164
|
+
const isSqlQueryPlan = (p: ExecutionPlan<Row> | SqlQueryPlan<Row>): p is SqlQueryPlan<Row> => {
|
|
165
|
+
return 'ast' in p && !('sql' in p);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const executablePlan: ExecutionPlan<Row> = isSqlQueryPlan(plan)
|
|
169
|
+
? lowerSqlPlan(this.adapter, this.contract, plan)
|
|
170
|
+
: plan;
|
|
171
|
+
|
|
172
|
+
const iterator = async function* (
|
|
173
|
+
self: SqlRuntimeImpl<TContract>,
|
|
174
|
+
): AsyncGenerator<Row, void, unknown> {
|
|
175
|
+
const encodedParams = encodeParams(
|
|
176
|
+
executablePlan,
|
|
177
|
+
self.codecRegistry,
|
|
178
|
+
self.jsonSchemaValidators,
|
|
179
|
+
);
|
|
180
|
+
const planWithEncodedParams: ExecutionPlan<Row> = {
|
|
181
|
+
...executablePlan,
|
|
182
|
+
params: encodedParams,
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const coreIterator = self.core.execute(planWithEncodedParams);
|
|
186
|
+
|
|
187
|
+
for await (const rawRow of coreIterator) {
|
|
188
|
+
const decodedRow = decodeRow(
|
|
189
|
+
rawRow as Record<string, unknown>,
|
|
190
|
+
executablePlan,
|
|
191
|
+
self.codecRegistry,
|
|
192
|
+
self.jsonSchemaValidators,
|
|
193
|
+
);
|
|
194
|
+
yield decodedRow as Row;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
return new AsyncIterableResult(iterator(this));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
connection(): Promise<RuntimeConnection> {
|
|
202
|
+
return this.core.connection();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
telemetry(): RuntimeTelemetryEvent | null {
|
|
206
|
+
return this.core.telemetry();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
operations(): OperationRegistry {
|
|
210
|
+
return this.core.operations();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
close(): Promise<void> {
|
|
214
|
+
return this.core.close();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function createRuntime<TContract extends SqlContract<SqlStorage>, TTargetId extends string>(
|
|
219
|
+
options: CreateRuntimeOptions<TContract, TTargetId>,
|
|
220
|
+
): Runtime {
|
|
221
|
+
const { stackInstance, context, driver, verify, plugins, mode, log } = options;
|
|
222
|
+
|
|
223
|
+
return new SqlRuntimeImpl({
|
|
224
|
+
context,
|
|
225
|
+
adapter: stackInstance.adapter,
|
|
226
|
+
driver,
|
|
227
|
+
verify,
|
|
228
|
+
...ifDefined('plugins', plugins),
|
|
229
|
+
...ifDefined('mode', mode),
|
|
230
|
+
...ifDefined('log', log),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { ExecutionPlan } from '@prisma-next/contract/types';
|
|
2
|
+
import { instantiateExecutionStack } from '@prisma-next/core-execution-plane/stack';
|
|
3
|
+
import type { AsyncIterableResult } from '@prisma-next/runtime-executor';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import type { Runtime } from '../src/exports';
|
|
6
|
+
import { createRuntime, createSqlExecutionStack } from '../src/exports';
|
|
7
|
+
import {
|
|
8
|
+
createStubAdapter,
|
|
9
|
+
createTestAdapterDescriptor,
|
|
10
|
+
createTestContext,
|
|
11
|
+
createTestContract,
|
|
12
|
+
createTestTargetDescriptor,
|
|
13
|
+
} from './utils';
|
|
14
|
+
|
|
15
|
+
class MockDriver {
|
|
16
|
+
private rows: ReadonlyArray<Record<string, unknown>> = [];
|
|
17
|
+
|
|
18
|
+
setRows(rows: ReadonlyArray<Record<string, unknown>>): void {
|
|
19
|
+
this.rows = rows;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async query<Row = Record<string, unknown>>(
|
|
23
|
+
_sql: string,
|
|
24
|
+
_params?: readonly unknown[],
|
|
25
|
+
): Promise<{ rows: ReadonlyArray<Row> }> {
|
|
26
|
+
return { rows: [] };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async *execute<Row = Record<string, unknown>>(_options: {
|
|
30
|
+
sql: string;
|
|
31
|
+
params: readonly unknown[];
|
|
32
|
+
}): AsyncIterable<Row> {
|
|
33
|
+
for (const row of this.rows) {
|
|
34
|
+
yield row as Row;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async acquireConnection(): Promise<never> {
|
|
39
|
+
throw new Error('Not implemented in mock');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async connect(): Promise<void> {}
|
|
43
|
+
|
|
44
|
+
async close(): Promise<void> {}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const fixtureContract = createTestContract({
|
|
48
|
+
schemaVersion: '1',
|
|
49
|
+
targetFamily: 'sql',
|
|
50
|
+
target: 'postgres',
|
|
51
|
+
storageHash: 'test-hash',
|
|
52
|
+
profileHash: 'test-profile-hash',
|
|
53
|
+
storage: {
|
|
54
|
+
tables: {
|
|
55
|
+
user: {
|
|
56
|
+
columns: {
|
|
57
|
+
id: { nativeType: 'int4', codecId: 'pg/int4@1', nullable: false },
|
|
58
|
+
email: { nativeType: 'text', codecId: 'pg/text@1', nullable: false },
|
|
59
|
+
},
|
|
60
|
+
uniques: [],
|
|
61
|
+
indexes: [],
|
|
62
|
+
foreignKeys: [],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
models: {},
|
|
67
|
+
relations: {},
|
|
68
|
+
mappings: { codecTypes: {}, operationTypes: {} },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
function createTestRuntime(mockDriver: MockDriver): Runtime {
|
|
72
|
+
const adapter = createStubAdapter();
|
|
73
|
+
const stack = createSqlExecutionStack({
|
|
74
|
+
target: createTestTargetDescriptor(),
|
|
75
|
+
adapter: createTestAdapterDescriptor(adapter),
|
|
76
|
+
extensionPacks: [],
|
|
77
|
+
});
|
|
78
|
+
const stackInstance = instantiateExecutionStack(stack);
|
|
79
|
+
const context = createTestContext(fixtureContract, adapter);
|
|
80
|
+
return createRuntime({
|
|
81
|
+
stackInstance,
|
|
82
|
+
context,
|
|
83
|
+
driver: mockDriver,
|
|
84
|
+
verify: { mode: 'onFirstUse', requireMarker: false },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
describe('SqlRuntime AsyncIterableResult integration', () => {
|
|
89
|
+
it('returns AsyncIterableResult from execute', async () => {
|
|
90
|
+
const driver = new MockDriver();
|
|
91
|
+
driver.setRows([
|
|
92
|
+
{ id: 1, email: 'test1@example.com' },
|
|
93
|
+
{ id: 2, email: 'test2@example.com' },
|
|
94
|
+
]);
|
|
95
|
+
const runtime = createTestRuntime(driver);
|
|
96
|
+
|
|
97
|
+
const plan: ExecutionPlan<{ id: number; email: string }> = {
|
|
98
|
+
sql: 'SELECT id, email FROM "user" ORDER BY id',
|
|
99
|
+
params: [],
|
|
100
|
+
meta: {
|
|
101
|
+
target: 'postgres',
|
|
102
|
+
targetFamily: 'sql',
|
|
103
|
+
storageHash: 'test-hash',
|
|
104
|
+
lane: 'sql',
|
|
105
|
+
paramDescriptors: [],
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const result = runtime.execute(plan);
|
|
110
|
+
|
|
111
|
+
expect(result).toBeInstanceOf(Object);
|
|
112
|
+
expect(typeof result.toArray).toBe('function');
|
|
113
|
+
expect(typeof result[Symbol.asyncIterator]).toBe('function');
|
|
114
|
+
|
|
115
|
+
await runtime.close();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('preserves type information', async () => {
|
|
119
|
+
const driver = new MockDriver();
|
|
120
|
+
driver.setRows([{ id: 1, email: 'test@example.com' }]);
|
|
121
|
+
const runtime = createTestRuntime(driver);
|
|
122
|
+
|
|
123
|
+
const plan: ExecutionPlan<{ id: number; email: string }> = {
|
|
124
|
+
sql: 'SELECT id, email FROM "user" LIMIT 1',
|
|
125
|
+
params: [],
|
|
126
|
+
meta: {
|
|
127
|
+
target: 'postgres',
|
|
128
|
+
targetFamily: 'sql',
|
|
129
|
+
storageHash: 'test-hash',
|
|
130
|
+
lane: 'sql',
|
|
131
|
+
paramDescriptors: [],
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const result: AsyncIterableResult<{ id: number; email: string }> = runtime.execute(plan);
|
|
136
|
+
const rows = await result.toArray();
|
|
137
|
+
|
|
138
|
+
expect(rows.length).toBe(1);
|
|
139
|
+
expect(typeof rows[0]!.id).toBe('number');
|
|
140
|
+
expect(typeof rows[0]!.email).toBe('string');
|
|
141
|
+
|
|
142
|
+
await runtime.close();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { SqlContract, SqlMappings, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
2
|
+
import { expectTypeOf, test } from 'vitest';
|
|
3
|
+
import type { ExecutionContext, TypeHelperRegistry } from '../src/sql-context';
|
|
4
|
+
|
|
5
|
+
// Contract type with storage.types using literal types (matching emission output)
|
|
6
|
+
type TestContract = SqlContract<
|
|
7
|
+
{
|
|
8
|
+
readonly tables: {
|
|
9
|
+
readonly document: {
|
|
10
|
+
readonly columns: {
|
|
11
|
+
readonly id: {
|
|
12
|
+
readonly nativeType: 'int4';
|
|
13
|
+
readonly codecId: 'pg/int4@1';
|
|
14
|
+
nullable: false;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
readonly primaryKey: { readonly columns: readonly ['id'] };
|
|
18
|
+
readonly uniques: readonly [];
|
|
19
|
+
readonly indexes: readonly [];
|
|
20
|
+
readonly foreignKeys: readonly [];
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
readonly types: {
|
|
24
|
+
readonly Vector1536: {
|
|
25
|
+
readonly codecId: 'pg/vector@1';
|
|
26
|
+
readonly nativeType: 'vector';
|
|
27
|
+
readonly typeParams: { readonly length: 1536 };
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
Record<string, never>,
|
|
32
|
+
Record<string, never>,
|
|
33
|
+
SqlMappings
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
test('ExecutionContext.types is TypeHelperRegistry', () => {
|
|
37
|
+
// ExecutionContext.types is intentionally loose (Record<string, unknown>)
|
|
38
|
+
// The strong typing comes from schema(context).types via ExtractSchemaTypes
|
|
39
|
+
expectTypeOf<ExecutionContext<TestContract>['types']>().toEqualTypeOf<TypeHelperRegistry>();
|
|
40
|
+
|
|
41
|
+
// TypeHelperRegistry allows any values - the actual type depends on init hooks
|
|
42
|
+
expectTypeOf<TypeHelperRegistry>().toEqualTypeOf<Record<string, unknown>>();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('ExecutionContext preserves contract type parameter', () => {
|
|
46
|
+
// Verify the contract type is preserved in ExecutionContext
|
|
47
|
+
expectTypeOf<ExecutionContext<TestContract>['contract']>().toEqualTypeOf<TestContract>();
|
|
48
|
+
|
|
49
|
+
// Verify we can access storage.types through the context's contract
|
|
50
|
+
type ContractStorageTypes = ExecutionContext<TestContract>['contract']['storage']['types'];
|
|
51
|
+
expectTypeOf<ContractStorageTypes>().toExtend<
|
|
52
|
+
| {
|
|
53
|
+
readonly Vector1536: {
|
|
54
|
+
readonly codecId: 'pg/vector@1';
|
|
55
|
+
readonly nativeType: 'vector';
|
|
56
|
+
readonly typeParams: { readonly length: 1536 };
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
| undefined
|
|
60
|
+
>();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('ExecutionContext accepts generic SqlContract', () => {
|
|
64
|
+
// Verify ExecutionContext defaults work
|
|
65
|
+
type DefaultContext = ExecutionContext;
|
|
66
|
+
expectTypeOf<DefaultContext['contract']>().toExtend<SqlContract<SqlStorage>>();
|
|
67
|
+
expectTypeOf<DefaultContext['types']>().toEqualTypeOf<TypeHelperRegistry>();
|
|
68
|
+
});
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { createExecutionStack } from '@prisma-next/core-execution-plane/stack';
|
|
2
|
+
import { codec, createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import { createExecutionContext, createSqlExecutionStack } from '../src/exports';
|
|
5
|
+
import type {
|
|
6
|
+
ExecutionContext,
|
|
7
|
+
SqlRuntimeAdapterDescriptor,
|
|
8
|
+
SqlRuntimeExtensionDescriptor,
|
|
9
|
+
SqlRuntimeTargetDescriptor,
|
|
10
|
+
} from '../src/sql-context';
|
|
11
|
+
import { createTestContract } from './utils';
|
|
12
|
+
|
|
13
|
+
function createStubAdapterDescriptor(): SqlRuntimeAdapterDescriptor<'postgres'> {
|
|
14
|
+
const registry = createCodecRegistry();
|
|
15
|
+
registry.register(
|
|
16
|
+
codec({
|
|
17
|
+
typeId: 'pg/text@1',
|
|
18
|
+
targetTypes: ['text'],
|
|
19
|
+
encode: (value: string) => value,
|
|
20
|
+
decode: (wire: string) => wire,
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
kind: 'adapter',
|
|
26
|
+
id: 'test-adapter',
|
|
27
|
+
version: '0.0.1',
|
|
28
|
+
familyId: 'sql' as const,
|
|
29
|
+
targetId: 'postgres' as const,
|
|
30
|
+
codecs: () => registry,
|
|
31
|
+
operationSignatures: () => [],
|
|
32
|
+
parameterizedCodecs: () => [],
|
|
33
|
+
create() {
|
|
34
|
+
return Object.assign(
|
|
35
|
+
{ familyId: 'sql' as const, targetId: 'postgres' as const },
|
|
36
|
+
{
|
|
37
|
+
profile: {
|
|
38
|
+
id: 'test-profile',
|
|
39
|
+
target: 'postgres',
|
|
40
|
+
capabilities: {},
|
|
41
|
+
codecs: () => registry,
|
|
42
|
+
},
|
|
43
|
+
lower() {
|
|
44
|
+
return {
|
|
45
|
+
profileId: 'test-profile',
|
|
46
|
+
body: Object.freeze({ sql: '', params: [] }),
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function createStubTargetDescriptor(): SqlRuntimeTargetDescriptor<'postgres'> {
|
|
56
|
+
return {
|
|
57
|
+
kind: 'target',
|
|
58
|
+
id: 'postgres',
|
|
59
|
+
version: '0.0.1',
|
|
60
|
+
familyId: 'sql' as const,
|
|
61
|
+
targetId: 'postgres' as const,
|
|
62
|
+
codecs: () => createCodecRegistry(),
|
|
63
|
+
operationSignatures: () => [],
|
|
64
|
+
parameterizedCodecs: () => [],
|
|
65
|
+
create() {
|
|
66
|
+
return { familyId: 'sql' as const, targetId: 'postgres' as const };
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function createStubExtensionDescriptor(): SqlRuntimeExtensionDescriptor<'postgres'> {
|
|
72
|
+
const registry = createCodecRegistry();
|
|
73
|
+
registry.register(
|
|
74
|
+
codec({
|
|
75
|
+
typeId: 'pg/uuid@1',
|
|
76
|
+
targetTypes: ['uuid'],
|
|
77
|
+
encode: (value: string) => value,
|
|
78
|
+
decode: (wire: string) => wire,
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const operations = [
|
|
83
|
+
{
|
|
84
|
+
forTypeId: 'pg/text@1',
|
|
85
|
+
method: 'example',
|
|
86
|
+
args: [],
|
|
87
|
+
returns: { kind: 'builtin' as const, type: 'string' as const },
|
|
88
|
+
lowering: {
|
|
89
|
+
targetFamily: 'sql' as const,
|
|
90
|
+
strategy: 'function' as const,
|
|
91
|
+
template: 'example({args})',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
kind: 'extension',
|
|
98
|
+
id: 'test-extension',
|
|
99
|
+
version: '0.0.1',
|
|
100
|
+
familyId: 'sql' as const,
|
|
101
|
+
targetId: 'postgres' as const,
|
|
102
|
+
codecs: () => registry,
|
|
103
|
+
operationSignatures: () => operations,
|
|
104
|
+
parameterizedCodecs: () => [],
|
|
105
|
+
create() {
|
|
106
|
+
return {
|
|
107
|
+
familyId: 'sql' as const,
|
|
108
|
+
targetId: 'postgres' as const,
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
describe('createExecutionStack', () => {
|
|
115
|
+
it('defaults driver to undefined and extensions to empty', () => {
|
|
116
|
+
const stack = createExecutionStack({
|
|
117
|
+
target: createStubTargetDescriptor(),
|
|
118
|
+
adapter: createStubAdapterDescriptor(),
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
expect(stack.driver).toBeUndefined();
|
|
122
|
+
expect(stack.extensionPacks).toEqual([]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('creates an execution context from descriptors-only stack', () => {
|
|
126
|
+
const contract = createTestContract({
|
|
127
|
+
storage: { tables: {} },
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const context = createExecutionContext({
|
|
131
|
+
contract,
|
|
132
|
+
stack: {
|
|
133
|
+
target: createStubTargetDescriptor(),
|
|
134
|
+
adapter: createStubAdapterDescriptor(),
|
|
135
|
+
extensionPacks: [createStubExtensionDescriptor()],
|
|
136
|
+
},
|
|
137
|
+
}) as ExecutionContext<typeof contract>;
|
|
138
|
+
|
|
139
|
+
expect(context.contract).toBe(contract);
|
|
140
|
+
expect(context.codecs.get('pg/text@1')).toBeDefined();
|
|
141
|
+
expect(context.codecs.get('pg/uuid@1')).toBeDefined();
|
|
142
|
+
expect(context.operations.byType('pg/text@1')).toHaveLength(1);
|
|
143
|
+
expect(context.types).toEqual({});
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('createSqlExecutionStack', () => {
|
|
148
|
+
it('preserves descriptor references and defaults extensions', () => {
|
|
149
|
+
const target = createStubTargetDescriptor();
|
|
150
|
+
const adapter = createStubAdapterDescriptor();
|
|
151
|
+
const stack = createSqlExecutionStack({ target, adapter });
|
|
152
|
+
|
|
153
|
+
expect(stack.target).toBe(target);
|
|
154
|
+
expect(stack.adapter).toBe(adapter);
|
|
155
|
+
expect(stack.extensionPacks).toEqual([]);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('keeps extension packs intact', () => {
|
|
159
|
+
const target = createStubTargetDescriptor();
|
|
160
|
+
const adapter = createStubAdapterDescriptor();
|
|
161
|
+
const extension = createStubExtensionDescriptor();
|
|
162
|
+
const stack = createSqlExecutionStack({ target, adapter, extensionPacks: [extension] });
|
|
163
|
+
|
|
164
|
+
expect(stack.extensionPacks).toEqual([extension]);
|
|
165
|
+
});
|
|
166
|
+
});
|