@prisma-next/sql-runtime 0.3.0-dev.11 → 0.3.0-dev.113
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-BKjZvwMh.mjs +971 -0
- package/dist/exports-BKjZvwMh.mjs.map +1 -0
- package/dist/index-eHiENgIB.d.mts +182 -0
- package/dist/index-eHiENgIB.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 +221 -0
- package/dist/test/utils.mjs.map +1 -0
- package/package.json +32 -25
- package/src/codecs/decoding.ts +84 -3
- package/src/codecs/encoding.ts +5 -15
- package/src/codecs/json-schema-validation.ts +61 -0
- package/src/exports/index.ts +19 -7
- package/src/lower-sql-plan.ts +8 -8
- package/src/plugins/budgets.ts +375 -0
- package/src/plugins/lints.ts +211 -0
- package/src/sql-context.ts +448 -98
- package/src/sql-family-adapter.ts +9 -5
- package/src/sql-marker.ts +2 -2
- package/src/sql-runtime.ts +126 -30
- package/test/async-iterable-result.test.ts +43 -35
- package/test/budgets.test.ts +481 -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 +575 -0
- package/test/lints.test.ts +161 -0
- package/test/mutation-default-generators.test.ts +256 -0
- package/test/parameterized-types.test.ts +536 -0
- package/test/sql-context.test.ts +293 -121
- package/test/sql-family-adapter.test.ts +8 -10
- package/test/sql-runtime.test.ts +219 -34
- package/test/utils.ts +90 -51
- package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js +0 -137863
- package/dist/accelerate-EEKAFGN3-P6A6XJWJ.js.map +0 -1
- package/dist/amcheck-24VY6X5V.js +0 -13
- package/dist/amcheck-24VY6X5V.js.map +0 -1
- package/dist/bloom-VS74NLHT.js +0 -13
- package/dist/bloom-VS74NLHT.js.map +0 -1
- package/dist/btree_gin-WBC4EAAI.js +0 -13
- package/dist/btree_gin-WBC4EAAI.js.map +0 -1
- package/dist/btree_gist-UNC6QD3M.js +0 -13
- package/dist/btree_gist-UNC6QD3M.js.map +0 -1
- package/dist/chunk-3KTOEDFX.js +0 -49
- package/dist/chunk-3KTOEDFX.js.map +0 -1
- package/dist/chunk-47DZBRQC.js +0 -1280
- package/dist/chunk-47DZBRQC.js.map +0 -1
- package/dist/chunk-52N6AFZM.js +0 -133
- package/dist/chunk-52N6AFZM.js.map +0 -1
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-7D4SUZUM.js.map +0 -1
- package/dist/chunk-C6I3V3DM.js +0 -455
- package/dist/chunk-C6I3V3DM.js.map +0 -1
- package/dist/chunk-ECWIHLAT.js +0 -37
- package/dist/chunk-ECWIHLAT.js.map +0 -1
- package/dist/chunk-EI626SDC.js +0 -105
- package/dist/chunk-EI626SDC.js.map +0 -1
- package/dist/chunk-UKKOYUGL.js +0 -578
- package/dist/chunk-UKKOYUGL.js.map +0 -1
- package/dist/chunk-XPLNMXQV.js +0 -1537
- package/dist/chunk-XPLNMXQV.js.map +0 -1
- package/dist/citext-T7MXGUY7.js +0 -13
- package/dist/citext-T7MXGUY7.js.map +0 -1
- package/dist/client-5FENX6AW.js +0 -299
- package/dist/client-5FENX6AW.js.map +0 -1
- package/dist/cube-TFDQBZCI.js +0 -13
- package/dist/cube-TFDQBZCI.js.map +0 -1
- package/dist/dict_int-AEUOPGWP.js +0 -13
- package/dist/dict_int-AEUOPGWP.js.map +0 -1
- package/dist/dict_xsyn-DAAYX3FL.js +0 -13
- package/dist/dict_xsyn-DAAYX3FL.js.map +0 -1
- package/dist/dist-AQ3LWXOX.js +0 -570
- package/dist/dist-AQ3LWXOX.js.map +0 -1
- package/dist/dist-LBVX6BJW.js +0 -189
- package/dist/dist-LBVX6BJW.js.map +0 -1
- package/dist/dist-WLKUVDN2.js +0 -5127
- package/dist/dist-WLKUVDN2.js.map +0 -1
- package/dist/earthdistance-KIGTF4LE.js +0 -13
- package/dist/earthdistance-KIGTF4LE.js.map +0 -1
- package/dist/file_fdw-5N55UP6I.js +0 -13
- package/dist/file_fdw-5N55UP6I.js.map +0 -1
- package/dist/fuzzystrmatch-KN3YWBFP.js +0 -13
- package/dist/fuzzystrmatch-KN3YWBFP.js.map +0 -1
- package/dist/hstore-YX726NKN.js +0 -13
- package/dist/hstore-YX726NKN.js.map +0 -1
- package/dist/http-exception-FZY2H4OF.js +0 -8
- package/dist/http-exception-FZY2H4OF.js.map +0 -1
- package/dist/index.js +0 -30
- package/dist/index.js.map +0 -1
- package/dist/intarray-NKVXNO2D.js +0 -13
- package/dist/intarray-NKVXNO2D.js.map +0 -1
- package/dist/isn-FTEMJGEV.js +0 -13
- package/dist/isn-FTEMJGEV.js.map +0 -1
- package/dist/lo-DB7L4NGI.js +0 -13
- package/dist/lo-DB7L4NGI.js.map +0 -1
- package/dist/logger-WQ7SHNDD.js +0 -68
- package/dist/logger-WQ7SHNDD.js.map +0 -1
- package/dist/ltree-Z32TZT6W.js +0 -13
- package/dist/ltree-Z32TZT6W.js.map +0 -1
- package/dist/nodefs-NM46ACH7.js +0 -31
- package/dist/nodefs-NM46ACH7.js.map +0 -1
- package/dist/opfs-ahp-NJO33LVZ.js +0 -332
- package/dist/opfs-ahp-NJO33LVZ.js.map +0 -1
- package/dist/pageinspect-YP3IZR4X.js +0 -13
- package/dist/pageinspect-YP3IZR4X.js.map +0 -1
- package/dist/pg_buffercache-7TD5J2FB.js +0 -13
- package/dist/pg_buffercache-7TD5J2FB.js.map +0 -1
- package/dist/pg_dump-SG4KYBUB.js +0 -2492
- package/dist/pg_dump-SG4KYBUB.js.map +0 -1
- package/dist/pg_freespacemap-DZDNCPZK.js +0 -13
- package/dist/pg_freespacemap-DZDNCPZK.js.map +0 -1
- package/dist/pg_surgery-J2MUEWEP.js +0 -13
- package/dist/pg_surgery-J2MUEWEP.js.map +0 -1
- package/dist/pg_trgm-7VNQOYS6.js +0 -13
- package/dist/pg_trgm-7VNQOYS6.js.map +0 -1
- package/dist/pg_visibility-TTSIPHFL.js +0 -13
- package/dist/pg_visibility-TTSIPHFL.js.map +0 -1
- package/dist/pg_walinspect-KPFHSHRJ.js +0 -13
- package/dist/pg_walinspect-KPFHSHRJ.js.map +0 -1
- package/dist/proxy-signals-GUDAMDHV.js +0 -39
- package/dist/proxy-signals-GUDAMDHV.js.map +0 -1
- package/dist/seg-IYVDLE4O.js +0 -13
- package/dist/seg-IYVDLE4O.js.map +0 -1
- package/dist/src/codecs/decoding.d.ts +0 -4
- package/dist/src/codecs/decoding.d.ts.map +0 -1
- package/dist/src/codecs/encoding.d.ts +0 -5
- package/dist/src/codecs/encoding.d.ts.map +0 -1
- package/dist/src/codecs/validation.d.ts +0 -6
- package/dist/src/codecs/validation.d.ts.map +0 -1
- package/dist/src/exports/index.d.ts +0 -11
- package/dist/src/exports/index.d.ts.map +0 -1
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/lower-sql-plan.d.ts +0 -15
- package/dist/src/lower-sql-plan.d.ts.map +0 -1
- package/dist/src/sql-context.d.ts +0 -65
- package/dist/src/sql-context.d.ts.map +0 -1
- package/dist/src/sql-family-adapter.d.ts +0 -10
- package/dist/src/sql-family-adapter.d.ts.map +0 -1
- package/dist/src/sql-marker.d.ts +0 -22
- package/dist/src/sql-marker.d.ts.map +0 -1
- package/dist/src/sql-runtime.d.ts +0 -25
- package/dist/src/sql-runtime.d.ts.map +0 -1
- package/dist/tablefunc-EF4RCS7S.js +0 -13
- package/dist/tablefunc-EF4RCS7S.js.map +0 -1
- package/dist/tcn-3VT5BQYW.js +0 -13
- package/dist/tcn-3VT5BQYW.js.map +0 -1
- package/dist/test/utils.d.ts +0 -59
- package/dist/test/utils.d.ts.map +0 -1
- package/dist/test/utils.js +0 -24634
- package/dist/test/utils.js.map +0 -1
- package/dist/tiny-CW6F4GX6.js +0 -10
- package/dist/tiny-CW6F4GX6.js.map +0 -1
- package/dist/tsm_system_rows-ES7KNUQH.js +0 -13
- package/dist/tsm_system_rows-ES7KNUQH.js.map +0 -1
- package/dist/tsm_system_time-76WEIMBG.js +0 -13
- package/dist/tsm_system_time-76WEIMBG.js.map +0 -1
- package/dist/unaccent-7RYF3R64.js +0 -13
- package/dist/unaccent-7RYF3R64.js.map +0 -1
- package/dist/utility-Q5A254LJ-J4HTKZPT.js +0 -347
- package/dist/utility-Q5A254LJ-J4HTKZPT.js.map +0 -1
- package/dist/uuid_ossp-4ETE4FPE.js +0 -13
- package/dist/uuid_ossp-4ETE4FPE.js.map +0 -1
- package/dist/vector-74GPNV7V.js +0 -13
- package/dist/vector-74GPNV7V.js.map +0 -1
- package/src/index.ts +0 -1
package/src/sql-context.ts
CHANGED
|
@@ -1,156 +1,506 @@
|
|
|
1
|
+
import { checkContractComponentRequirements } from '@prisma-next/contract/framework-components';
|
|
2
|
+
import type { ExecutionMutationDefaultValue } from '@prisma-next/contract/types';
|
|
3
|
+
import { createExecutionStack, type ExecutionStack } from '@prisma-next/core-execution-plane/stack';
|
|
1
4
|
import type {
|
|
2
5
|
RuntimeAdapterDescriptor,
|
|
3
6
|
RuntimeAdapterInstance,
|
|
7
|
+
RuntimeDriverDescriptor,
|
|
8
|
+
RuntimeDriverInstance,
|
|
4
9
|
RuntimeExtensionDescriptor,
|
|
5
10
|
RuntimeExtensionInstance,
|
|
6
11
|
RuntimeTargetDescriptor,
|
|
12
|
+
RuntimeTargetInstance,
|
|
7
13
|
} from '@prisma-next/core-execution-plane/types';
|
|
8
14
|
import { createOperationRegistry } from '@prisma-next/operations';
|
|
9
|
-
import
|
|
15
|
+
import { runtimeError } from '@prisma-next/runtime-executor';
|
|
16
|
+
import type { SqlContract, SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
10
17
|
import type { SqlOperationSignature } from '@prisma-next/sql-operations';
|
|
11
18
|
import type {
|
|
12
19
|
Adapter,
|
|
20
|
+
AnyQueryAst,
|
|
21
|
+
CodecParamsDescriptor,
|
|
13
22
|
CodecRegistry,
|
|
14
23
|
LoweredStatement,
|
|
15
|
-
|
|
24
|
+
SqlDriver,
|
|
16
25
|
} from '@prisma-next/sql-relational-core/ast';
|
|
17
26
|
import { createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
|
|
18
|
-
import type {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
import type {
|
|
28
|
+
AppliedMutationDefault,
|
|
29
|
+
ExecutionContext,
|
|
30
|
+
JsonSchemaValidateFn,
|
|
31
|
+
JsonSchemaValidatorRegistry,
|
|
32
|
+
MutationDefaultsOptions,
|
|
33
|
+
TypeHelperRegistry,
|
|
34
|
+
} from '@prisma-next/sql-relational-core/query-lane-context';
|
|
35
|
+
import type { QueryOperationDescriptor } from '@prisma-next/sql-relational-core/query-operations';
|
|
36
|
+
import { createQueryOperationRegistry } from '@prisma-next/sql-relational-core/query-operations';
|
|
37
|
+
import { type as arktype } from 'arktype';
|
|
23
38
|
|
|
24
39
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
40
|
+
* Runtime parameterized codec descriptor.
|
|
41
|
+
* Provides validation schema and optional init hook for codecs that support type parameters.
|
|
42
|
+
* Used at runtime to validate typeParams and create type helpers.
|
|
28
43
|
*
|
|
29
|
-
*
|
|
44
|
+
* This is a type alias for `CodecParamsDescriptor` from the AST layer,
|
|
45
|
+
* which is the shared definition used by both adapter and runtime.
|
|
30
46
|
*/
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
export type RuntimeParameterizedCodecDescriptor<
|
|
48
|
+
TParams = Record<string, unknown>,
|
|
49
|
+
THelper = unknown,
|
|
50
|
+
> = CodecParamsDescriptor<TParams, THelper>;
|
|
51
|
+
|
|
52
|
+
export interface SqlStaticContributions {
|
|
53
|
+
readonly codecs: () => CodecRegistry;
|
|
54
|
+
readonly operationSignatures: () => ReadonlyArray<SqlOperationSignature>;
|
|
55
|
+
// biome-ignore lint/suspicious/noExplicitAny: needed for covariance with concrete descriptor types
|
|
56
|
+
readonly parameterizedCodecs: () => ReadonlyArray<RuntimeParameterizedCodecDescriptor<any, any>>;
|
|
57
|
+
readonly queryOperations?: () => ReadonlyArray<QueryOperationDescriptor>;
|
|
58
|
+
readonly mutationDefaultGenerators?: () => ReadonlyArray<RuntimeMutationDefaultGenerator>;
|
|
37
59
|
}
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
extends
|
|
61
|
+
export interface RuntimeMutationDefaultGenerator {
|
|
62
|
+
readonly id: string;
|
|
63
|
+
readonly generate: (params?: Record<string, unknown>) => unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface SqlRuntimeTargetDescriptor<
|
|
67
|
+
TTargetId extends string = string,
|
|
68
|
+
TTargetInstance extends RuntimeTargetInstance<'sql', TTargetId> = RuntimeTargetInstance<
|
|
69
|
+
'sql',
|
|
70
|
+
TTargetId
|
|
71
|
+
>,
|
|
72
|
+
> extends RuntimeTargetDescriptor<'sql', TTargetId, TTargetInstance>,
|
|
73
|
+
SqlStaticContributions {}
|
|
74
|
+
|
|
75
|
+
export interface SqlRuntimeAdapterDescriptor<
|
|
76
|
+
TTargetId extends string = string,
|
|
77
|
+
TAdapterInstance extends RuntimeAdapterInstance<
|
|
78
|
+
'sql',
|
|
79
|
+
TTargetId
|
|
80
|
+
> = SqlRuntimeAdapterInstance<TTargetId>,
|
|
81
|
+
> extends RuntimeAdapterDescriptor<'sql', TTargetId, TAdapterInstance>,
|
|
82
|
+
SqlStaticContributions {}
|
|
83
|
+
|
|
84
|
+
export interface SqlRuntimeExtensionDescriptor<TTargetId extends string = string>
|
|
85
|
+
extends RuntimeExtensionDescriptor<'sql', TTargetId, SqlRuntimeExtensionInstance<TTargetId>>,
|
|
86
|
+
SqlStaticContributions {
|
|
47
87
|
create(): SqlRuntimeExtensionInstance<TTargetId>;
|
|
48
88
|
}
|
|
49
89
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
90
|
+
export interface SqlExecutionStack<TTargetId extends string = string> {
|
|
91
|
+
readonly target: SqlRuntimeTargetDescriptor<TTargetId>;
|
|
92
|
+
readonly adapter: SqlRuntimeAdapterDescriptor<TTargetId>;
|
|
93
|
+
readonly extensionPacks: readonly SqlRuntimeExtensionDescriptor<TTargetId>[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type SqlExecutionStackWithDriver<TTargetId extends string = string> = Omit<
|
|
97
|
+
ExecutionStack<
|
|
98
|
+
'sql',
|
|
99
|
+
TTargetId,
|
|
100
|
+
SqlRuntimeAdapterInstance<TTargetId>,
|
|
101
|
+
SqlRuntimeDriverInstance<TTargetId>,
|
|
102
|
+
SqlRuntimeExtensionInstance<TTargetId>
|
|
103
|
+
>,
|
|
104
|
+
'target' | 'adapter' | 'driver' | 'extensionPacks'
|
|
105
|
+
> & {
|
|
106
|
+
readonly target: SqlRuntimeTargetDescriptor<TTargetId>;
|
|
107
|
+
readonly adapter: SqlRuntimeAdapterDescriptor<TTargetId, SqlRuntimeAdapterInstance<TTargetId>>;
|
|
108
|
+
readonly driver:
|
|
109
|
+
| RuntimeDriverDescriptor<'sql', TTargetId, unknown, SqlRuntimeDriverInstance<TTargetId>>
|
|
110
|
+
| undefined;
|
|
111
|
+
readonly extensionPacks: readonly SqlRuntimeExtensionDescriptor<TTargetId>[];
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export interface SqlRuntimeExtensionInstance<TTargetId extends string>
|
|
115
|
+
extends RuntimeExtensionInstance<'sql', TTargetId> {}
|
|
116
|
+
|
|
117
|
+
export type SqlRuntimeAdapterInstance<TTargetId extends string = string> = RuntimeAdapterInstance<
|
|
118
|
+
'sql',
|
|
119
|
+
TTargetId
|
|
120
|
+
> &
|
|
121
|
+
Adapter<AnyQueryAst, SqlContract<SqlStorage>, LoweredStatement>;
|
|
53
122
|
|
|
54
123
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
124
|
+
* NOTE: Binding type is intentionally erased to unknown at this shared runtime layer.
|
|
125
|
+
* Target clients (for example `postgres()`) validate and construct the concrete binding
|
|
126
|
+
* before calling `driver.connect(binding)`, which keeps runtime behavior safe today.
|
|
127
|
+
* A future follow-up can preserve TBinding through stack/context generics end-to-end.
|
|
60
128
|
*/
|
|
61
|
-
export type
|
|
129
|
+
export type SqlRuntimeDriverInstance<TTargetId extends string = string> = RuntimeDriverInstance<
|
|
62
130
|
'sql',
|
|
63
131
|
TTargetId
|
|
64
132
|
> &
|
|
65
|
-
|
|
133
|
+
SqlDriver<unknown>;
|
|
134
|
+
|
|
135
|
+
export function createSqlExecutionStack<TTargetId extends string>(options: {
|
|
136
|
+
readonly target: SqlRuntimeTargetDescriptor<TTargetId>;
|
|
137
|
+
readonly adapter: SqlRuntimeAdapterDescriptor<TTargetId>;
|
|
138
|
+
readonly driver?:
|
|
139
|
+
| RuntimeDriverDescriptor<'sql', TTargetId, unknown, SqlRuntimeDriverInstance<TTargetId>>
|
|
140
|
+
| undefined;
|
|
141
|
+
readonly extensionPacks?: readonly SqlRuntimeExtensionDescriptor<TTargetId>[] | undefined;
|
|
142
|
+
}): SqlExecutionStackWithDriver<TTargetId> {
|
|
143
|
+
return createExecutionStack({
|
|
144
|
+
target: options.target,
|
|
145
|
+
adapter: options.adapter,
|
|
146
|
+
driver: options.driver,
|
|
147
|
+
extensionPacks: options.extensionPacks,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type { ExecutionContext, JsonSchemaValidatorRegistry, TypeHelperRegistry };
|
|
152
|
+
|
|
153
|
+
export function assertExecutionStackContractRequirements(
|
|
154
|
+
contract: SqlContract<SqlStorage>,
|
|
155
|
+
stack: SqlExecutionStack,
|
|
156
|
+
): void {
|
|
157
|
+
const providedComponentIds = new Set<string>([
|
|
158
|
+
stack.target.id,
|
|
159
|
+
stack.adapter.id,
|
|
160
|
+
...stack.extensionPacks.map((pack) => pack.id),
|
|
161
|
+
]);
|
|
66
162
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
163
|
+
const result = checkContractComponentRequirements({
|
|
164
|
+
contract,
|
|
165
|
+
expectedTargetFamily: 'sql',
|
|
166
|
+
expectedTargetId: stack.target.targetId,
|
|
167
|
+
providedComponentIds,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (result.familyMismatch) {
|
|
171
|
+
throw runtimeError(
|
|
172
|
+
'RUNTIME.CONTRACT_FAMILY_MISMATCH',
|
|
173
|
+
`Contract target family '${result.familyMismatch.actual}' does not match runtime family '${result.familyMismatch.expected}'.`,
|
|
174
|
+
{
|
|
175
|
+
actual: result.familyMismatch.actual,
|
|
176
|
+
expected: result.familyMismatch.expected,
|
|
177
|
+
},
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (result.targetMismatch) {
|
|
182
|
+
throw runtimeError(
|
|
183
|
+
'RUNTIME.CONTRACT_TARGET_MISMATCH',
|
|
184
|
+
`Contract target '${result.targetMismatch.actual}' does not match runtime target descriptor '${result.targetMismatch.expected}'.`,
|
|
185
|
+
{
|
|
186
|
+
actual: result.targetMismatch.actual,
|
|
187
|
+
expected: result.targetMismatch.expected,
|
|
188
|
+
},
|
|
189
|
+
);
|
|
190
|
+
}
|
|
70
191
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
192
|
+
if (result.missingExtensionPackIds.length > 0) {
|
|
193
|
+
const packIds = result.missingExtensionPackIds;
|
|
194
|
+
const packList = packIds.map((id) => `'${id}'`).join(', ');
|
|
195
|
+
throw runtimeError(
|
|
196
|
+
'RUNTIME.MISSING_EXTENSION_PACK',
|
|
197
|
+
`Contract requires extension pack(s) ${packList}, but runtime descriptors do not provide matching component(s).`,
|
|
198
|
+
{ packIds },
|
|
199
|
+
);
|
|
200
|
+
}
|
|
76
201
|
}
|
|
77
202
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
>;
|
|
96
|
-
|
|
203
|
+
function validateTypeParams(
|
|
204
|
+
typeParams: Record<string, unknown>,
|
|
205
|
+
codecDescriptor: RuntimeParameterizedCodecDescriptor,
|
|
206
|
+
context: { typeName?: string; tableName?: string; columnName?: string },
|
|
207
|
+
): Record<string, unknown> {
|
|
208
|
+
const result = codecDescriptor.paramsSchema(typeParams);
|
|
209
|
+
if (result instanceof arktype.errors) {
|
|
210
|
+
const messages = result.map((p: { message: string }) => p.message).join('; ');
|
|
211
|
+
const locationInfo = context.typeName
|
|
212
|
+
? `type '${context.typeName}'`
|
|
213
|
+
: `column '${context.tableName}.${context.columnName}'`;
|
|
214
|
+
throw runtimeError(
|
|
215
|
+
'RUNTIME.TYPE_PARAMS_INVALID',
|
|
216
|
+
`Invalid typeParams for ${locationInfo} (codecId: ${codecDescriptor.codecId}): ${messages}`,
|
|
217
|
+
{ ...context, codecId: codecDescriptor.codecId, typeParams },
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
return result as Record<string, unknown>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function collectParameterizedCodecDescriptors(
|
|
224
|
+
contributors: ReadonlyArray<SqlStaticContributions>,
|
|
225
|
+
): Map<string, RuntimeParameterizedCodecDescriptor> {
|
|
226
|
+
const descriptors = new Map<string, RuntimeParameterizedCodecDescriptor>();
|
|
227
|
+
|
|
228
|
+
for (const contributor of contributors) {
|
|
229
|
+
for (const descriptor of contributor.parameterizedCodecs()) {
|
|
230
|
+
if (descriptors.has(descriptor.codecId)) {
|
|
231
|
+
throw runtimeError(
|
|
232
|
+
'RUNTIME.DUPLICATE_PARAMETERIZED_CODEC',
|
|
233
|
+
`Duplicate parameterized codec descriptor for codecId '${descriptor.codecId}'.`,
|
|
234
|
+
{ codecId: descriptor.codecId },
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
descriptors.set(descriptor.codecId, descriptor);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return descriptors;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function initializeTypeHelpers(
|
|
245
|
+
storageTypes: Record<string, StorageTypeInstance> | undefined,
|
|
246
|
+
codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
|
|
247
|
+
): TypeHelperRegistry {
|
|
248
|
+
const helpers: TypeHelperRegistry = {};
|
|
249
|
+
|
|
250
|
+
if (!storageTypes) {
|
|
251
|
+
return helpers;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
for (const [typeName, typeInstance] of Object.entries(storageTypes)) {
|
|
255
|
+
const descriptor = codecDescriptors.get(typeInstance.codecId);
|
|
256
|
+
|
|
257
|
+
if (descriptor) {
|
|
258
|
+
const validatedParams = validateTypeParams(typeInstance.typeParams, descriptor, {
|
|
259
|
+
typeName,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
if (descriptor.init) {
|
|
263
|
+
helpers[typeName] = descriptor.init(validatedParams);
|
|
264
|
+
} else {
|
|
265
|
+
helpers[typeName] = typeInstance;
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
helpers[typeName] = typeInstance;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return helpers;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function validateColumnTypeParams(
|
|
276
|
+
storage: SqlStorage,
|
|
277
|
+
codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
|
|
278
|
+
): void {
|
|
279
|
+
for (const [tableName, table] of Object.entries(storage.tables)) {
|
|
280
|
+
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
281
|
+
if (column.typeParams) {
|
|
282
|
+
const descriptor = codecDescriptors.get(column.codecId);
|
|
283
|
+
if (descriptor) {
|
|
284
|
+
validateTypeParams(column.typeParams, descriptor, { tableName, columnName });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
97
289
|
}
|
|
98
290
|
|
|
99
291
|
/**
|
|
100
|
-
*
|
|
292
|
+
* Builds a registry of compiled JSON Schema validators by scanning the contract
|
|
293
|
+
* for columns whose codec descriptor provides an `init` hook returning `{ validate }`.
|
|
101
294
|
*
|
|
102
|
-
*
|
|
103
|
-
* -
|
|
104
|
-
* -
|
|
105
|
-
* - Codec registry (populated from adapter + extension instances)
|
|
106
|
-
* - Operation registry (populated from extension instances)
|
|
107
|
-
*
|
|
108
|
-
* @param options - Descriptor-first composition options
|
|
109
|
-
* @returns RuntimeContext with registries wired from all components
|
|
295
|
+
* Handles both:
|
|
296
|
+
* - Inline `typeParams.schema` on columns
|
|
297
|
+
* - `typeRef` → `storage.types[ref]` with init hook results already in `types` registry
|
|
110
298
|
*/
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
299
|
+
function buildJsonSchemaValidatorRegistry(
|
|
300
|
+
contract: SqlContract<SqlStorage>,
|
|
301
|
+
types: TypeHelperRegistry,
|
|
302
|
+
codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
|
|
303
|
+
): JsonSchemaValidatorRegistry | undefined {
|
|
304
|
+
const validators = new Map<string, JsonSchemaValidateFn>();
|
|
116
305
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
const
|
|
306
|
+
// Collect codec IDs that have init hooks (these produce { validate } helpers)
|
|
307
|
+
const codecIdsWithInit = new Set<string>();
|
|
308
|
+
for (const [codecId, descriptor] of codecDescriptors) {
|
|
309
|
+
if (descriptor.init) {
|
|
310
|
+
codecIdsWithInit.add(codecId);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
120
313
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
314
|
+
if (codecIdsWithInit.size === 0) {
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
for (const [tableName, table] of Object.entries(contract.storage.tables)) {
|
|
319
|
+
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
320
|
+
if (!codecIdsWithInit.has(column.codecId)) continue;
|
|
321
|
+
|
|
322
|
+
const key = `${tableName}.${columnName}`;
|
|
124
323
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
324
|
+
// Case 1: column references a named type → validator already compiled via init hook
|
|
325
|
+
if (column.typeRef) {
|
|
326
|
+
const helper = types[column.typeRef] as { validate?: JsonSchemaValidateFn } | undefined;
|
|
327
|
+
if (helper?.validate) {
|
|
328
|
+
validators.set(key, helper.validate);
|
|
329
|
+
}
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Case 2: inline typeParams with schema → compile via init hook
|
|
334
|
+
if (column.typeParams) {
|
|
335
|
+
const descriptor = codecDescriptors.get(column.codecId);
|
|
336
|
+
if (descriptor?.init) {
|
|
337
|
+
const helper = descriptor.init(column.typeParams) as
|
|
338
|
+
| { validate?: JsonSchemaValidateFn }
|
|
339
|
+
| undefined;
|
|
340
|
+
if (helper?.validate) {
|
|
341
|
+
validators.set(key, helper.validate);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
129
346
|
}
|
|
130
347
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
348
|
+
if (validators.size === 0) return undefined;
|
|
349
|
+
return {
|
|
350
|
+
get: (key: string) => validators.get(key),
|
|
351
|
+
size: validators.size,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function collectMutationDefaultGenerators(
|
|
356
|
+
contributors: ReadonlyArray<SqlStaticContributions & { readonly id: string }>,
|
|
357
|
+
): ReadonlyMap<string, RuntimeMutationDefaultGenerator> {
|
|
358
|
+
const generators = new Map<string, RuntimeMutationDefaultGenerator>();
|
|
359
|
+
const owners = new Map<string, string>();
|
|
134
360
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
361
|
+
for (const contributor of contributors) {
|
|
362
|
+
const nextGenerators = contributor.mutationDefaultGenerators?.() ?? [];
|
|
363
|
+
for (const generator of nextGenerators) {
|
|
364
|
+
const existingOwner = owners.get(generator.id);
|
|
365
|
+
if (existingOwner !== undefined) {
|
|
366
|
+
throw runtimeError(
|
|
367
|
+
'RUNTIME.DUPLICATE_MUTATION_DEFAULT_GENERATOR',
|
|
368
|
+
`Duplicate mutation default generator '${generator.id}'.`,
|
|
369
|
+
{
|
|
370
|
+
id: generator.id,
|
|
371
|
+
existingOwner,
|
|
372
|
+
incomingOwner: contributor.id,
|
|
373
|
+
},
|
|
374
|
+
);
|
|
139
375
|
}
|
|
376
|
+
generators.set(generator.id, generator);
|
|
377
|
+
owners.set(generator.id, contributor.id);
|
|
140
378
|
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return generators;
|
|
382
|
+
}
|
|
141
383
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
384
|
+
function computeExecutionDefaultValue(
|
|
385
|
+
spec: ExecutionMutationDefaultValue,
|
|
386
|
+
generatorRegistry: ReadonlyMap<string, RuntimeMutationDefaultGenerator>,
|
|
387
|
+
): unknown {
|
|
388
|
+
switch (spec.kind) {
|
|
389
|
+
case 'generator': {
|
|
390
|
+
const generator = generatorRegistry.get(spec.id);
|
|
391
|
+
if (!generator) {
|
|
392
|
+
throw runtimeError(
|
|
393
|
+
'RUNTIME.MUTATION_DEFAULT_GENERATOR_MISSING',
|
|
394
|
+
`Contract references mutation default generator '${spec.id}' but no runtime component provides it.`,
|
|
395
|
+
{
|
|
396
|
+
id: spec.id,
|
|
397
|
+
},
|
|
398
|
+
);
|
|
146
399
|
}
|
|
400
|
+
// nosemgrep: javascript.express.security.express-wkhtml-injection.express-wkhtmltoimage-injection
|
|
401
|
+
return generator.generate(spec.params);
|
|
147
402
|
}
|
|
148
403
|
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function applyMutationDefaults(
|
|
407
|
+
contract: SqlContract<SqlStorage>,
|
|
408
|
+
generatorRegistry: ReadonlyMap<string, RuntimeMutationDefaultGenerator>,
|
|
409
|
+
options: MutationDefaultsOptions,
|
|
410
|
+
): ReadonlyArray<AppliedMutationDefault> {
|
|
411
|
+
const defaults = contract.execution?.mutations.defaults ?? [];
|
|
412
|
+
if (defaults.length === 0) {
|
|
413
|
+
return [];
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const applied: AppliedMutationDefault[] = [];
|
|
417
|
+
const appliedColumns = new Set<string>();
|
|
418
|
+
|
|
419
|
+
for (const mutationDefault of defaults) {
|
|
420
|
+
if (mutationDefault.ref.table !== options.table) {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const defaultSpec =
|
|
425
|
+
options.op === 'create' ? mutationDefault.onCreate : mutationDefault.onUpdate;
|
|
426
|
+
if (!defaultSpec) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const columnName = mutationDefault.ref.column;
|
|
431
|
+
if (Object.hasOwn(options.values, columnName) || appliedColumns.has(columnName)) {
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
applied.push({
|
|
436
|
+
column: columnName,
|
|
437
|
+
value: computeExecutionDefaultValue(defaultSpec, generatorRegistry),
|
|
438
|
+
});
|
|
439
|
+
appliedColumns.add(columnName);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return applied;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export function createExecutionContext<
|
|
446
|
+
TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>,
|
|
447
|
+
TTargetId extends string = string,
|
|
448
|
+
>(options: {
|
|
449
|
+
readonly contract: TContract;
|
|
450
|
+
readonly stack: SqlExecutionStack<TTargetId>;
|
|
451
|
+
}): ExecutionContext<TContract> {
|
|
452
|
+
const { contract, stack } = options;
|
|
453
|
+
|
|
454
|
+
assertExecutionStackContractRequirements(contract, stack);
|
|
455
|
+
|
|
456
|
+
const codecRegistry = createCodecRegistry();
|
|
457
|
+
const operationRegistry = createOperationRegistry();
|
|
458
|
+
|
|
459
|
+
const contributors: Array<SqlStaticContributions & { readonly id: string }> = [
|
|
460
|
+
stack.target,
|
|
461
|
+
stack.adapter,
|
|
462
|
+
...stack.extensionPacks,
|
|
463
|
+
];
|
|
464
|
+
|
|
465
|
+
for (const contributor of contributors) {
|
|
466
|
+
for (const c of contributor.codecs().values()) {
|
|
467
|
+
codecRegistry.register(c);
|
|
468
|
+
}
|
|
469
|
+
for (const operation of contributor.operationSignatures()) {
|
|
470
|
+
operationRegistry.register(operation);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const queryOperationRegistry = createQueryOperationRegistry();
|
|
475
|
+
for (const contributor of contributors) {
|
|
476
|
+
for (const op of contributor.queryOperations?.() ?? []) {
|
|
477
|
+
queryOperationRegistry.register(op);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const parameterizedCodecDescriptors = collectParameterizedCodecDescriptors(contributors);
|
|
482
|
+
const mutationDefaultGeneratorRegistry = collectMutationDefaultGenerators(contributors);
|
|
483
|
+
|
|
484
|
+
if (parameterizedCodecDescriptors.size > 0) {
|
|
485
|
+
validateColumnTypeParams(contract.storage, parameterizedCodecDescriptors);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const types = initializeTypeHelpers(contract.storage.types, parameterizedCodecDescriptors);
|
|
489
|
+
|
|
490
|
+
const jsonSchemaValidators = buildJsonSchemaValidatorRegistry(
|
|
491
|
+
contract,
|
|
492
|
+
types,
|
|
493
|
+
parameterizedCodecDescriptors,
|
|
494
|
+
);
|
|
149
495
|
|
|
150
496
|
return {
|
|
151
497
|
contract,
|
|
152
|
-
adapter: adapterInstance,
|
|
153
498
|
operations: operationRegistry,
|
|
154
499
|
codecs: codecRegistry,
|
|
500
|
+
queryOperations: queryOperationRegistry,
|
|
501
|
+
types,
|
|
502
|
+
...(jsonSchemaValidators ? { jsonSchemaValidators } : {}),
|
|
503
|
+
applyMutationDefaults: (options) =>
|
|
504
|
+
applyMutationDefaults(contract, mutationDefaultGeneratorRegistry, options),
|
|
155
505
|
};
|
|
156
506
|
}
|
|
@@ -33,11 +33,15 @@ export class SqlFamilyAdapter<TContract extends SqlContract<SqlStorage>>
|
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
if (plan.meta.
|
|
37
|
-
throw runtimeError(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
if (plan.meta.storageHash !== contract.storageHash) {
|
|
37
|
+
throw runtimeError(
|
|
38
|
+
'PLAN.HASH_MISMATCH',
|
|
39
|
+
'Plan storage hash does not match runtime contract',
|
|
40
|
+
{
|
|
41
|
+
planStorageHash: plan.meta.storageHash,
|
|
42
|
+
runtimeStorageHash: contract.storageHash,
|
|
43
|
+
},
|
|
44
|
+
);
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
47
|
}
|
package/src/sql-marker.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface SqlStatement {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export interface WriteMarkerInput {
|
|
9
|
-
readonly
|
|
9
|
+
readonly storageHash: string;
|
|
10
10
|
readonly profileHash: string;
|
|
11
11
|
readonly contractJson?: unknown;
|
|
12
12
|
readonly canonicalVersion?: number;
|
|
@@ -57,7 +57,7 @@ export interface WriteContractMarkerStatements {
|
|
|
57
57
|
export function writeContractMarker(input: WriteMarkerInput): WriteContractMarkerStatements {
|
|
58
58
|
const baseParams: readonly unknown[] = [
|
|
59
59
|
1,
|
|
60
|
-
input.
|
|
60
|
+
input.storageHash,
|
|
61
61
|
input.profileHash,
|
|
62
62
|
input.contractJson ?? null,
|
|
63
63
|
input.canonicalVersion ?? null,
|