@prisma-next/sql-runtime 0.13.0-dev.3 → 0.13.0-dev.31
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 +24 -43
- package/dist/{exports-DDqF-xmg.mjs → exports-DJWGwqMq.mjs} +71 -115
- package/dist/exports-DJWGwqMq.mjs.map +1 -0
- package/dist/index.d.mts +80 -2
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -2
- package/dist/{index-JOQlRa75.d.mts → prepared-statement-FQyyQnkC.d.mts} +172 -107
- package/dist/prepared-statement-FQyyQnkC.d.mts.map +1 -0
- package/dist/test/utils.d.mts +17 -6
- package/dist/test/utils.d.mts.map +1 -1
- package/dist/test/utils.mjs +22 -3
- package/dist/test/utils.mjs.map +1 -1
- package/package.json +12 -12
- package/src/codecs/ast-codec-resolver.ts +2 -44
- package/src/codecs/validation.ts +19 -30
- package/src/exports/index.ts +6 -2
- package/src/runtime-spi.ts +1 -1
- package/src/sql-context.ts +15 -56
- package/src/sql-runtime.ts +39 -48
- package/dist/exports-DDqF-xmg.mjs.map +0 -1
- package/dist/index-JOQlRa75.d.mts.map +0 -1
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-runtime",
|
|
3
|
-
"version": "0.13.0-dev.
|
|
3
|
+
"version": "0.13.0-dev.31",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "SQL runtime implementation for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/contract": "0.13.0-dev.
|
|
10
|
-
"@prisma-next/utils": "0.13.0-dev.
|
|
11
|
-
"@prisma-next/framework-components": "0.13.0-dev.
|
|
12
|
-
"@prisma-next/ids": "0.13.0-dev.
|
|
13
|
-
"@prisma-next/operations": "0.13.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract": "0.13.0-dev.
|
|
15
|
-
"@prisma-next/sql-operations": "0.13.0-dev.
|
|
16
|
-
"@prisma-next/sql-relational-core": "0.13.0-dev.
|
|
9
|
+
"@prisma-next/contract": "0.13.0-dev.31",
|
|
10
|
+
"@prisma-next/utils": "0.13.0-dev.31",
|
|
11
|
+
"@prisma-next/framework-components": "0.13.0-dev.31",
|
|
12
|
+
"@prisma-next/ids": "0.13.0-dev.31",
|
|
13
|
+
"@prisma-next/operations": "0.13.0-dev.31",
|
|
14
|
+
"@prisma-next/sql-contract": "0.13.0-dev.31",
|
|
15
|
+
"@prisma-next/sql-operations": "0.13.0-dev.31",
|
|
16
|
+
"@prisma-next/sql-relational-core": "0.13.0-dev.31",
|
|
17
17
|
"arktype": "^2.2.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@prisma-next/test-utils": "0.13.0-dev.
|
|
21
|
-
"@prisma-next/tsconfig": "0.13.0-dev.
|
|
20
|
+
"@prisma-next/test-utils": "0.13.0-dev.31",
|
|
21
|
+
"@prisma-next/tsconfig": "0.13.0-dev.31",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.21.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.13.0-dev.
|
|
24
|
+
"@prisma-next/tsdown": "0.13.0-dev.31",
|
|
25
25
|
"tsdown": "0.22.1",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.8"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CodecRef } from '@prisma-next/framework-components/codec';
|
|
2
|
+
import { materializeCodec } from '@prisma-next/framework-components/codec';
|
|
2
3
|
import { runtimeError } from '@prisma-next/framework-components/runtime';
|
|
3
4
|
import { canonicalizeJson } from '@prisma-next/framework-components/utils';
|
|
4
5
|
import type { Codec, SqlCodecInstanceContext } from '@prisma-next/sql-relational-core/ast';
|
|
@@ -46,54 +47,11 @@ export function createAstCodecResolver(
|
|
|
46
47
|
);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
// Parameterized codecs whose paramsSchema accepts `{}` (every field
|
|
50
|
-
// optional, e.g. `pg/timestamptz@1` precision) tolerate refs that omit
|
|
51
|
-
// `typeParams` entirely. Normalize `undefined` to `{}` at the validation
|
|
52
|
-
// boundary; the integrity check upstream already rejected refs whose
|
|
53
|
-
// schemas reject the empty object.
|
|
54
|
-
const validated = validateTypeParams(
|
|
55
|
-
descriptor.paramsSchema,
|
|
56
|
-
descriptor.isParameterized && ref.typeParams === undefined
|
|
57
|
-
? { ...ref, typeParams: {} }
|
|
58
|
-
: ref,
|
|
59
|
-
);
|
|
60
50
|
const ctx = instanceContextFor(ref);
|
|
61
|
-
|
|
62
|
-
const codec = (
|
|
63
|
-
descriptor.factory as (params: unknown) => (ctx: SqlCodecInstanceContext) => Codec
|
|
64
|
-
)(validated)(ctx);
|
|
51
|
+
const codec = materializeCodec(descriptor, ref, ctx);
|
|
65
52
|
|
|
66
53
|
cache.set(key, codec);
|
|
67
54
|
return codec;
|
|
68
55
|
},
|
|
69
56
|
};
|
|
70
57
|
}
|
|
71
|
-
|
|
72
|
-
function validateTypeParams(
|
|
73
|
-
paramsSchema: { '~standard': { validate: (input: unknown) => unknown } },
|
|
74
|
-
ref: CodecRef,
|
|
75
|
-
): unknown {
|
|
76
|
-
const result = paramsSchema['~standard'].validate(ref.typeParams) as
|
|
77
|
-
| { value: unknown }
|
|
78
|
-
| { issues: ReadonlyArray<{ message: string }> }
|
|
79
|
-
| Promise<unknown>;
|
|
80
|
-
|
|
81
|
-
if (result instanceof Promise) {
|
|
82
|
-
throw runtimeError(
|
|
83
|
-
'RUNTIME.TYPE_PARAMS_INVALID',
|
|
84
|
-
`paramsSchema for codec '${ref.codecId}' returned a Promise; runtime validation requires a synchronous Standard Schema validator.`,
|
|
85
|
-
{ codecId: ref.codecId, typeParams: ref.typeParams },
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if ('issues' in result && result.issues) {
|
|
90
|
-
const messages = result.issues.map((issue) => issue.message).join('; ');
|
|
91
|
-
throw runtimeError(
|
|
92
|
-
'RUNTIME.TYPE_PARAMS_INVALID',
|
|
93
|
-
`Invalid typeParams for codec '${ref.codecId}': ${messages}`,
|
|
94
|
-
{ codecId: ref.codecId, typeParams: ref.typeParams },
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return (result as { value: unknown }).value;
|
|
99
|
-
}
|
package/src/codecs/validation.ts
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
2
|
import { runtimeError } from '@prisma-next/framework-components/runtime';
|
|
3
|
-
import type { SqlStorage
|
|
3
|
+
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
4
4
|
import type { CodecDescriptorRegistry } from '@prisma-next/sql-relational-core/query-lane-context';
|
|
5
5
|
|
|
6
|
-
// Framework `Namespace.tables` is widened to `Record<string, object>` so
|
|
7
|
-
// emitted `contract.d.ts` table literals (which omit the optional `kind`
|
|
8
|
-
// discriminator) satisfy it structurally. At runtime, every `SqlStorage`
|
|
9
|
-
// namespace holds `StorageTable` instances — the constructor enforces it.
|
|
10
|
-
// Narrowing per-iteration via a single-step cast (not `as unknown as`)
|
|
11
|
-
// keeps Pattern C walks readable without weakening the substrate type.
|
|
12
|
-
type SqlNamespaceTables = Readonly<Record<string, StorageTable>>;
|
|
13
|
-
|
|
14
6
|
export function extractCodecIds(contract: Contract<SqlStorage>): Set<string> {
|
|
15
7
|
const codecIds = new Set<string>();
|
|
16
8
|
|
|
17
9
|
for (const ns of Object.values(contract.storage.namespaces)) {
|
|
18
|
-
for (const table of Object.values(ns.entries.table
|
|
10
|
+
for (const table of Object.values(ns.entries.table ?? {})) {
|
|
19
11
|
for (const column of Object.values(table.columns)) {
|
|
20
12
|
const codecId = column.codecId;
|
|
21
13
|
codecIds.add(codecId);
|
|
@@ -26,37 +18,34 @@ export function extractCodecIds(contract: Contract<SqlStorage>): Set<string> {
|
|
|
26
18
|
return codecIds;
|
|
27
19
|
}
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
type ColumnCodecRef = {
|
|
22
|
+
readonly namespaceId: string;
|
|
23
|
+
readonly table: string;
|
|
24
|
+
readonly column: string;
|
|
25
|
+
readonly codecId: string;
|
|
26
|
+
};
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
function extractColumnCodecRefs(contract: Contract<SqlStorage>): ColumnCodecRef[] {
|
|
29
|
+
const refs: ColumnCodecRef[] = [];
|
|
30
|
+
|
|
31
|
+
for (const [namespaceId, ns] of Object.entries(contract.storage.namespaces)) {
|
|
32
|
+
for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
|
|
34
33
|
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
35
|
-
|
|
36
|
-
const key = `${tableName}.${columnName}`;
|
|
37
|
-
codecIds.set(key, codecId);
|
|
34
|
+
refs.push({ namespaceId, table: tableName, column: columnName, codecId: column.codecId });
|
|
38
35
|
}
|
|
39
36
|
}
|
|
40
37
|
}
|
|
41
38
|
|
|
42
|
-
return
|
|
39
|
+
return refs;
|
|
43
40
|
}
|
|
44
41
|
|
|
45
42
|
export function validateContractCodecMappings(
|
|
46
43
|
registry: CodecDescriptorRegistry,
|
|
47
44
|
contract: Contract<SqlStorage>,
|
|
48
45
|
): void {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
for (const [key, codecId] of codecIds.entries()) {
|
|
53
|
-
if (registry.descriptorFor(codecId) === undefined) {
|
|
54
|
-
const parts = key.split('.');
|
|
55
|
-
const table = parts[0] ?? '';
|
|
56
|
-
const column = parts[1] ?? '';
|
|
57
|
-
invalidCodecs.push({ table, column, codecId });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
46
|
+
const invalidCodecs = extractColumnCodecRefs(contract).filter(
|
|
47
|
+
(ref) => registry.descriptorFor(ref.codecId) === undefined,
|
|
48
|
+
);
|
|
60
49
|
|
|
61
50
|
if (invalidCodecs.length > 0) {
|
|
62
51
|
const details: Record<string, unknown> = {
|
|
@@ -66,7 +55,7 @@ export function validateContractCodecMappings(
|
|
|
66
55
|
|
|
67
56
|
throw runtimeError(
|
|
68
57
|
'RUNTIME.CODEC_MISSING',
|
|
69
|
-
`Missing codec implementations for column codecIds: ${invalidCodecs.map((c) => `${c.table}.${c.column} (${c.codecId})`).join(', ')}`,
|
|
58
|
+
`Missing codec implementations for column codecIds: ${invalidCodecs.map((c) => `${c.namespaceId}.${c.table}.${c.column} (${c.codecId})`).join(', ')}`,
|
|
70
59
|
details,
|
|
71
60
|
);
|
|
72
61
|
}
|
package/src/exports/index.ts
CHANGED
|
@@ -16,6 +16,10 @@ export { budgets } from '../middleware/budgets';
|
|
|
16
16
|
export type { LintsOptions } from '../middleware/lints';
|
|
17
17
|
export { lints } from '../middleware/lints';
|
|
18
18
|
export type { SqlMiddleware, SqlMiddlewareContext } from '../middleware/sql-middleware';
|
|
19
|
+
export {
|
|
20
|
+
PreparedStatementImpl,
|
|
21
|
+
type PreparedStatementInternals,
|
|
22
|
+
} from '../prepared/prepared-statement';
|
|
19
23
|
export type {
|
|
20
24
|
BindSiteParams,
|
|
21
25
|
Declaration,
|
|
@@ -54,11 +58,11 @@ export {
|
|
|
54
58
|
createSqlExecutionStack,
|
|
55
59
|
} from '../sql-context';
|
|
56
60
|
export type {
|
|
57
|
-
|
|
61
|
+
ConnectionProvider,
|
|
58
62
|
Runtime,
|
|
59
63
|
RuntimeConnection,
|
|
60
64
|
RuntimeQueryable,
|
|
61
65
|
RuntimeTransaction,
|
|
62
66
|
TransactionContext,
|
|
63
67
|
} from '../sql-runtime';
|
|
64
|
-
export {
|
|
68
|
+
export { SqlRuntimeBase, withTransaction } from '../sql-runtime';
|
package/src/runtime-spi.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface MarkerReader {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* SQL family adapter SPI consumed by `
|
|
12
|
+
* SQL family adapter SPI consumed by `SqlRuntimeBase`. Encapsulates the
|
|
13
13
|
* runtime contract, marker reader, and plan validation logic so the
|
|
14
14
|
* runtime can be unit-tested without a concrete SQL adapter profile.
|
|
15
15
|
*
|
package/src/sql-context.ts
CHANGED
|
@@ -27,11 +27,7 @@ import {
|
|
|
27
27
|
} from '@prisma-next/framework-components/execution';
|
|
28
28
|
import { runtimeError } from '@prisma-next/framework-components/runtime';
|
|
29
29
|
import { canonicalizeJson } from '@prisma-next/framework-components/utils';
|
|
30
|
-
import {
|
|
31
|
-
isPostgresEnumStorageEntry,
|
|
32
|
-
type SqlStorage,
|
|
33
|
-
type StorageTypeInstance,
|
|
34
|
-
} from '@prisma-next/sql-contract/types';
|
|
30
|
+
import type { SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
35
31
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
36
32
|
|
|
37
33
|
function documentScopedCodecTypes(
|
|
@@ -241,30 +237,6 @@ export function assertExecutionStackContractRequirements(
|
|
|
241
237
|
}
|
|
242
238
|
}
|
|
243
239
|
|
|
244
|
-
/**
|
|
245
|
-
* Resolves codec id + typeParams for a `SqlStorage.types` entry that
|
|
246
|
-
* represents an enum. The canonical contract path always pipes raw JSON
|
|
247
|
-
* through the `SqlStorage` constructor, which rejects raw
|
|
248
|
-
* `kind: 'postgres-enum'` envelopes that bypass the per-target
|
|
249
|
-
* `ContractSerializer.deserializeContract` hydration. By the time this
|
|
250
|
-
* function runs, the entry is a live IR-class instance that
|
|
251
|
-
* structurally satisfies `PostgresEnumStorageEntry` — `codecId` and
|
|
252
|
-
* `values` are enumerable own properties on the instance. Returns
|
|
253
|
-
* `undefined` when the entry is not enum-shaped, so callers fall
|
|
254
|
-
* through to the codec-typed path.
|
|
255
|
-
*/
|
|
256
|
-
function readEnumViewIfApplicable(
|
|
257
|
-
typeInstance: unknown,
|
|
258
|
-
): { readonly codecId: string; readonly typeParams: Record<string, unknown> } | undefined {
|
|
259
|
-
if (!isPostgresEnumStorageEntry(typeInstance)) {
|
|
260
|
-
return undefined;
|
|
261
|
-
}
|
|
262
|
-
return {
|
|
263
|
-
codecId: typeInstance.codecId,
|
|
264
|
-
typeParams: { values: typeInstance.values },
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
240
|
function validateTypeParams(
|
|
269
241
|
typeParams: Record<string, unknown>,
|
|
270
242
|
descriptor: RuntimeParameterizedCodecDescriptor,
|
|
@@ -335,7 +307,7 @@ function collectTypeRefSites(
|
|
|
335
307
|
): Map<string, Array<{ readonly table: string; readonly column: string }>> {
|
|
336
308
|
const sites = new Map<string, Array<{ readonly table: string; readonly column: string }>>();
|
|
337
309
|
for (const ns of Object.values(storage.namespaces)) {
|
|
338
|
-
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
310
|
+
for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
|
|
339
311
|
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
340
312
|
if (typeof column.typeRef !== 'string') continue;
|
|
341
313
|
const list = sites.get(column.typeRef);
|
|
@@ -365,11 +337,8 @@ function initializeTypeHelpers(
|
|
|
365
337
|
const typeRefSites = collectTypeRefSites(storage);
|
|
366
338
|
|
|
367
339
|
for (const [typeName, typeInstance] of Object.entries(documentTypes)) {
|
|
368
|
-
const
|
|
369
|
-
const
|
|
370
|
-
const typeParams = enumView
|
|
371
|
-
? enumView.typeParams
|
|
372
|
-
: (typeInstance as StorageTypeInstance).typeParams;
|
|
340
|
+
const codecId = typeInstance.codecId;
|
|
341
|
+
const typeParams = typeInstance.typeParams;
|
|
373
342
|
const descriptor = codecDescriptors.get(codecId);
|
|
374
343
|
|
|
375
344
|
if (!descriptor) {
|
|
@@ -397,7 +366,7 @@ function validateColumnTypeParams(
|
|
|
397
366
|
codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
|
|
398
367
|
): void {
|
|
399
368
|
for (const ns of Object.values(storage.namespaces)) {
|
|
400
|
-
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
369
|
+
for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
|
|
401
370
|
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
402
371
|
if (column.typeParams) {
|
|
403
372
|
const descriptor = codecDescriptors.get(column.codecId);
|
|
@@ -426,7 +395,7 @@ function assertColumnCodecIntegrity(
|
|
|
426
395
|
codecDescriptors: CodecDescriptorRegistry,
|
|
427
396
|
): void {
|
|
428
397
|
for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {
|
|
429
|
-
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
398
|
+
for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
|
|
430
399
|
for (const columnName of Object.keys(table.columns)) {
|
|
431
400
|
const ref = codecDescriptors.codecRefForColumn(namespaceId, tableName, columnName);
|
|
432
401
|
if (!ref) continue;
|
|
@@ -533,25 +502,15 @@ function buildContractCodecRegistry(
|
|
|
533
502
|
|
|
534
503
|
const typeRefSites = collectTypeRefSites(contract.storage);
|
|
535
504
|
for (const [typeName, typeInstance] of Object.entries(documentScopedCodecTypes(contract) ?? {})) {
|
|
536
|
-
const
|
|
537
|
-
const instanceTypeParams = enumView
|
|
538
|
-
? enumView.typeParams
|
|
539
|
-
: (typeInstance as StorageTypeInstance).typeParams;
|
|
505
|
+
const instanceTypeParams = typeInstance.typeParams;
|
|
540
506
|
const hasParamKeys =
|
|
541
507
|
instanceTypeParams !== undefined && Object.keys(instanceTypeParams).length > 0;
|
|
542
|
-
const ref: CodecRef =
|
|
543
|
-
?
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
: { codecId: enumView.codecId }
|
|
549
|
-
: hasParamKeys
|
|
550
|
-
? {
|
|
551
|
-
codecId: (typeInstance as StorageTypeInstance).codecId,
|
|
552
|
-
typeParams: instanceTypeParams as JsonValue,
|
|
553
|
-
}
|
|
554
|
-
: { codecId: (typeInstance as StorageTypeInstance).codecId };
|
|
508
|
+
const ref: CodecRef = hasParamKeys
|
|
509
|
+
? {
|
|
510
|
+
codecId: typeInstance.codecId,
|
|
511
|
+
typeParams: instanceTypeParams as JsonValue,
|
|
512
|
+
}
|
|
513
|
+
: { codecId: typeInstance.codecId };
|
|
555
514
|
const key = refKeyOf(ref);
|
|
556
515
|
const sites = typeRefSites.get(typeName) ?? [];
|
|
557
516
|
const existing = usedAtByKey.get(key);
|
|
@@ -565,7 +524,7 @@ function buildContractCodecRegistry(
|
|
|
565
524
|
}
|
|
566
525
|
|
|
567
526
|
for (const [namespaceId, ns] of Object.entries(contract.storage.namespaces)) {
|
|
568
|
-
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
527
|
+
for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
|
|
569
528
|
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
570
529
|
if (column.typeRef !== undefined) continue;
|
|
571
530
|
const ref = codecDescriptors.codecRefForColumn(namespaceId, tableName, columnName);
|
|
@@ -597,7 +556,7 @@ function buildContractCodecRegistry(
|
|
|
597
556
|
});
|
|
598
557
|
|
|
599
558
|
for (const [namespaceId, ns] of Object.entries(contract.storage.namespaces)) {
|
|
600
|
-
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
559
|
+
for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
|
|
601
560
|
for (const columnName of Object.keys(table.columns)) {
|
|
602
561
|
const ref = codecDescriptors.codecRefForColumn(namespaceId, tableName, columnName);
|
|
603
562
|
if (!ref) continue;
|
package/src/sql-runtime.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
|
-
import type {
|
|
3
|
-
ExecutionStackInstance,
|
|
4
|
-
RuntimeDriverInstance,
|
|
5
|
-
} from '@prisma-next/framework-components/execution';
|
|
6
2
|
import {
|
|
7
3
|
AsyncIterableResult,
|
|
8
4
|
checkAborted,
|
|
@@ -23,6 +19,7 @@ import type {
|
|
|
23
19
|
LoweredStatement,
|
|
24
20
|
PreparedExecuteRequest,
|
|
25
21
|
SqlCodecCallContext,
|
|
22
|
+
SqlConnection,
|
|
26
23
|
SqlDriver,
|
|
27
24
|
SqlQueryable,
|
|
28
25
|
SqlTransaction,
|
|
@@ -64,11 +61,7 @@ import type {
|
|
|
64
61
|
TelemetryOutcome,
|
|
65
62
|
VerifyMarkerOption,
|
|
66
63
|
} from './runtime-spi';
|
|
67
|
-
import type {
|
|
68
|
-
ExecutionContext,
|
|
69
|
-
SqlRuntimeAdapterInstance,
|
|
70
|
-
SqlRuntimeExtensionInstance,
|
|
71
|
-
} from './sql-context';
|
|
64
|
+
import type { ExecutionContext } from './sql-context';
|
|
72
65
|
import { SqlFamilyAdapter } from './sql-family-adapter';
|
|
73
66
|
|
|
74
67
|
export type Log = RuntimeLog;
|
|
@@ -83,25 +76,10 @@ export interface RuntimeOptions<TContract extends Contract<SqlStorage> = Contrac
|
|
|
83
76
|
readonly log?: Log;
|
|
84
77
|
}
|
|
85
78
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
readonly stackInstance: ExecutionStackInstance<
|
|
91
|
-
'sql',
|
|
92
|
-
TTargetId,
|
|
93
|
-
SqlRuntimeAdapterInstance<TTargetId>,
|
|
94
|
-
RuntimeDriverInstance<'sql', TTargetId>,
|
|
95
|
-
SqlRuntimeExtensionInstance<TTargetId>
|
|
96
|
-
>;
|
|
97
|
-
readonly context: ExecutionContext<TContract>;
|
|
98
|
-
readonly driver: SqlDriver<unknown>;
|
|
99
|
-
readonly verifyMarker?: VerifyMarkerOption;
|
|
100
|
-
readonly middleware?: readonly SqlMiddleware[];
|
|
101
|
-
readonly mode?: 'strict' | 'permissive';
|
|
102
|
-
readonly log?: Log;
|
|
103
|
-
}
|
|
104
|
-
|
|
79
|
+
/**
|
|
80
|
+
* SQL-family runtime interface. Named `Runtime` (not `SqlRuntime`) by deliberate exception
|
|
81
|
+
* to avoid a repo-wide rename; see ADR 230 (runtime target layer) for the recorded decision.
|
|
82
|
+
*/
|
|
105
83
|
export interface Runtime extends RuntimeQueryable {
|
|
106
84
|
connection(): Promise<RuntimeConnection>;
|
|
107
85
|
telemetry(): RuntimeTelemetryEvent | null;
|
|
@@ -167,7 +145,12 @@ function isExecutionPlan(plan: SqlExecutionPlan | SqlQueryPlan): plan is SqlExec
|
|
|
167
145
|
const noopLogSink = (): void => {};
|
|
168
146
|
const noopLog: Log = { info: noopLogSink, warn: noopLogSink, error: noopLogSink };
|
|
169
147
|
|
|
170
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Abstract family-layer base for SQL runtimes. Subclass to build a target runtime
|
|
150
|
+
* (e.g. `PostgresRuntimeImpl`); app code should consume the `Runtime` interface returned
|
|
151
|
+
* by the target factories, never this class directly.
|
|
152
|
+
*/
|
|
153
|
+
export abstract class SqlRuntimeBase<TContract extends Contract<SqlStorage> = Contract<SqlStorage>>
|
|
171
154
|
extends RuntimeCore<SqlQueryPlan, SqlExecutionPlan, SqlMiddleware>
|
|
172
155
|
implements Runtime
|
|
173
156
|
{
|
|
@@ -325,6 +308,16 @@ class SqlRuntimeImpl<TContract extends Contract<SqlStorage> = Contract<SqlStorag
|
|
|
325
308
|
);
|
|
326
309
|
}
|
|
327
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Returns the raw driver connection. The connection is a `SqlQueryable` — SQL
|
|
313
|
+
* issued on it runs below the middleware/codec/telemetry pipeline. It carries
|
|
314
|
+
* its own lifecycle (`release`/`destroy`/`beginTransaction`); the caller owns
|
|
315
|
+
* disposal.
|
|
316
|
+
*/
|
|
317
|
+
protected acquireRawConnection(): Promise<SqlConnection> {
|
|
318
|
+
return this.driver.acquireConnection();
|
|
319
|
+
}
|
|
320
|
+
|
|
328
321
|
private async *streamRows<Row>(
|
|
329
322
|
exec: SqlExecutionPlan,
|
|
330
323
|
decodeContext: DecodeContext,
|
|
@@ -385,7 +378,12 @@ class SqlRuntimeImpl<TContract extends Contract<SqlStorage> = Contract<SqlStorag
|
|
|
385
378
|
}
|
|
386
379
|
}
|
|
387
380
|
|
|
388
|
-
|
|
381
|
+
/**
|
|
382
|
+
* Execute a plan against a caller-supplied queryable, running the full
|
|
383
|
+
* middleware/codec/telemetry pipeline. Use `acquireRawConnection` to obtain a
|
|
384
|
+
* queryable that subclasses can bind typed plans to.
|
|
385
|
+
*/
|
|
386
|
+
protected executeAgainstQueryable<Row>(
|
|
389
387
|
plan: SqlExecutionPlan<unknown> | SqlQueryPlan<unknown>,
|
|
390
388
|
queryable: SqlQueryable,
|
|
391
389
|
options?: RuntimeExecuteOptions,
|
|
@@ -526,7 +524,11 @@ class SqlRuntimeImpl<TContract extends Contract<SqlStorage> = Contract<SqlStorag
|
|
|
526
524
|
return new PreparedStatementImpl<ParamsFromDeclaration<D, CT>, Row>(internals);
|
|
527
525
|
}
|
|
528
526
|
|
|
529
|
-
|
|
527
|
+
/**
|
|
528
|
+
* Execute a prepared statement against a caller-supplied queryable, running
|
|
529
|
+
* the full middleware/codec/telemetry pipeline.
|
|
530
|
+
*/
|
|
531
|
+
protected executePreparedAgainstQueryable<P, Row>(
|
|
530
532
|
ps: PreparedStatementImpl<P, Row>,
|
|
531
533
|
userParams: Record<string, unknown>,
|
|
532
534
|
queryable: SqlQueryable,
|
|
@@ -753,8 +755,13 @@ function transactionClosedError(): Error {
|
|
|
753
755
|
);
|
|
754
756
|
}
|
|
755
757
|
|
|
758
|
+
/** Minimal structural type `withTransaction` depends on — anything that can open a connection. */
|
|
759
|
+
export interface ConnectionProvider {
|
|
760
|
+
connection(): Promise<RuntimeConnection>;
|
|
761
|
+
}
|
|
762
|
+
|
|
756
763
|
export async function withTransaction<R>(
|
|
757
|
-
runtime:
|
|
764
|
+
runtime: ConnectionProvider,
|
|
758
765
|
fn: (tx: TransactionContext) => PromiseLike<R>,
|
|
759
766
|
): Promise<R> {
|
|
760
767
|
const connection = await runtime.connection();
|
|
@@ -859,19 +866,3 @@ export async function withTransaction<R>(
|
|
|
859
866
|
}
|
|
860
867
|
}
|
|
861
868
|
}
|
|
862
|
-
|
|
863
|
-
export function createRuntime<TContract extends Contract<SqlStorage>, TTargetId extends string>(
|
|
864
|
-
options: CreateRuntimeOptions<TContract, TTargetId>,
|
|
865
|
-
): Runtime {
|
|
866
|
-
const { stackInstance, context, driver, verifyMarker, middleware, mode, log } = options;
|
|
867
|
-
|
|
868
|
-
return new SqlRuntimeImpl({
|
|
869
|
-
context,
|
|
870
|
-
adapter: stackInstance.adapter,
|
|
871
|
-
driver,
|
|
872
|
-
...ifDefined('verifyMarker', verifyMarker),
|
|
873
|
-
...ifDefined('middleware', middleware),
|
|
874
|
-
...ifDefined('mode', mode),
|
|
875
|
-
...ifDefined('log', log),
|
|
876
|
-
});
|
|
877
|
-
}
|