@prisma-next/sql-runtime 0.3.0-dev.9 → 0.3.0-pr.100.2
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/dist/{chunk-C6I3V3DM.js → chunk-APA6GHYY.js} +84 -2
- package/dist/chunk-APA6GHYY.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/src/exports/index.d.ts +1 -1
- package/dist/src/exports/index.d.ts.map +1 -1
- package/dist/src/sql-context.d.ts +66 -1
- package/dist/src/sql-context.d.ts.map +1 -1
- package/dist/test/utils.d.ts +3 -2
- package/dist/test/utils.d.ts.map +1 -1
- package/dist/test/utils.js +9 -8
- package/dist/test/utils.js.map +1 -1
- package/package.json +15 -14
- package/src/exports/index.ts +2 -0
- package/src/sql-context.ts +249 -3
- package/test/context.types.test-d.ts +70 -0
- package/test/parameterized-types.test.ts +553 -0
- package/test/utils.ts +14 -10
- package/dist/chunk-C6I3V3DM.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-runtime",
|
|
3
|
-
"version": "0.3.0-
|
|
3
|
+
"version": "0.3.0-pr.100.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "SQL runtime implementation for Prisma Next",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"
|
|
9
|
-
"@prisma-next/contract": "0.3.0-
|
|
10
|
-
"@prisma-next/
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/
|
|
13
|
-
"@prisma-next/sql-
|
|
14
|
-
"@prisma-next/sql-
|
|
8
|
+
"arktype": "^2.1.26",
|
|
9
|
+
"@prisma-next/contract": "0.3.0-pr.100.2",
|
|
10
|
+
"@prisma-next/core-execution-plane": "0.3.0-pr.100.2",
|
|
11
|
+
"@prisma-next/operations": "0.3.0-pr.100.2",
|
|
12
|
+
"@prisma-next/runtime-executor": "0.3.0-pr.100.2",
|
|
13
|
+
"@prisma-next/sql-contract": "0.3.0-pr.100.2",
|
|
14
|
+
"@prisma-next/sql-operations": "0.3.0-pr.100.2",
|
|
15
|
+
"@prisma-next/sql-relational-core": "0.3.0-pr.100.2"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@types/pg": "8.16.0",
|
|
18
|
-
"@vitest/coverage-v8": "4.0.16",
|
|
19
19
|
"pg": "8.16.3",
|
|
20
20
|
"tsup": "8.5.1",
|
|
21
21
|
"typescript": "5.9.3",
|
|
22
22
|
"vitest": "4.0.16",
|
|
23
|
-
"@prisma-next/test-utils": "0.0.1"
|
|
23
|
+
"@prisma-next/test-utils": "0.0.1",
|
|
24
|
+
"@prisma-next/tsconfig": "0.0.0"
|
|
24
25
|
},
|
|
25
26
|
"files": [
|
|
26
27
|
"dist",
|
|
@@ -42,9 +43,9 @@
|
|
|
42
43
|
"test": "vitest run --passWithNoTests",
|
|
43
44
|
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
44
45
|
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
45
|
-
"lint": "biome check . --
|
|
46
|
-
"lint:fix": "biome check --write .
|
|
47
|
-
"lint:fix:unsafe": "biome check --write --unsafe .
|
|
48
|
-
"clean": "
|
|
46
|
+
"lint": "biome check . --error-on-warnings",
|
|
47
|
+
"lint:fix": "biome check --write .",
|
|
48
|
+
"lint:fix:unsafe": "biome check --write --unsafe .",
|
|
49
|
+
"clean": "rm -rf dist dist-tsc dist-tsc-prod coverage .tmp-output"
|
|
49
50
|
}
|
|
50
51
|
}
|
package/src/exports/index.ts
CHANGED
|
@@ -16,9 +16,11 @@ export { lowerSqlPlan } from '../lower-sql-plan';
|
|
|
16
16
|
export type {
|
|
17
17
|
CreateRuntimeContextOptions,
|
|
18
18
|
RuntimeContext,
|
|
19
|
+
RuntimeParameterizedCodecDescriptor,
|
|
19
20
|
SqlRuntimeAdapterInstance,
|
|
20
21
|
SqlRuntimeExtensionDescriptor,
|
|
21
22
|
SqlRuntimeExtensionInstance,
|
|
23
|
+
TypeHelperRegistry,
|
|
22
24
|
} from '../sql-context';
|
|
23
25
|
export { createRuntimeContext } from '../sql-context';
|
|
24
26
|
export type { SqlStatement } from '../sql-marker';
|
package/src/sql-context.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
RuntimeTargetDescriptor,
|
|
7
7
|
} from '@prisma-next/core-execution-plane/types';
|
|
8
8
|
import { createOperationRegistry } from '@prisma-next/operations';
|
|
9
|
-
import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
9
|
+
import type { SqlContract, SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
10
10
|
import type { SqlOperationSignature } from '@prisma-next/sql-operations';
|
|
11
11
|
import type {
|
|
12
12
|
Adapter,
|
|
@@ -15,7 +15,42 @@ import type {
|
|
|
15
15
|
QueryAst,
|
|
16
16
|
} from '@prisma-next/sql-relational-core/ast';
|
|
17
17
|
import { createCodecRegistry } from '@prisma-next/sql-relational-core/ast';
|
|
18
|
-
import type {
|
|
18
|
+
import type {
|
|
19
|
+
QueryLaneContext,
|
|
20
|
+
TypeHelperRegistry,
|
|
21
|
+
} from '@prisma-next/sql-relational-core/query-lane-context';
|
|
22
|
+
import type { Type } from 'arktype';
|
|
23
|
+
import { type as arktype } from 'arktype';
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Runtime Parameterized Codec Descriptor Types
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Runtime parameterized codec descriptor.
|
|
31
|
+
* Provides validation schema and optional init hook for codecs that support type parameters.
|
|
32
|
+
* Used at runtime to validate typeParams and create type helpers.
|
|
33
|
+
*/
|
|
34
|
+
export interface RuntimeParameterizedCodecDescriptor<
|
|
35
|
+
TParams = Record<string, unknown>,
|
|
36
|
+
THelper = unknown,
|
|
37
|
+
> {
|
|
38
|
+
/** The codec ID this descriptor applies to (e.g., 'pg/vector@1') */
|
|
39
|
+
readonly codecId: string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Arktype schema for validating typeParams.
|
|
43
|
+
* The schema is used to validate both storage.types entries and inline column typeParams.
|
|
44
|
+
*/
|
|
45
|
+
readonly paramsSchema: Type<TParams>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Optional init hook called during runtime context creation.
|
|
49
|
+
* Receives validated params and returns a helper object to be stored in context.types.
|
|
50
|
+
* If not provided, the validated params are stored directly.
|
|
51
|
+
*/
|
|
52
|
+
readonly init?: (params: TParams) => THelper;
|
|
53
|
+
}
|
|
19
54
|
|
|
20
55
|
// ============================================================================
|
|
21
56
|
// SQL Runtime Extension Types
|
|
@@ -34,6 +69,12 @@ export interface SqlRuntimeExtensionInstance<TTargetId extends string>
|
|
|
34
69
|
codecs?(): CodecRegistry;
|
|
35
70
|
/** Returns operations to register in the runtime context. */
|
|
36
71
|
operations?(): ReadonlyArray<SqlOperationSignature>;
|
|
72
|
+
/**
|
|
73
|
+
* Returns parameterized codec descriptors for type validation and helper creation.
|
|
74
|
+
* Uses unknown for type parameters to allow any concrete descriptor types.
|
|
75
|
+
*/
|
|
76
|
+
// biome-ignore lint/suspicious/noExplicitAny: needed for covariance with concrete descriptor types
|
|
77
|
+
parameterizedCodecs?(): ReadonlyArray<RuntimeParameterizedCodecDescriptor<any, any>>;
|
|
37
78
|
}
|
|
38
79
|
|
|
39
80
|
/**
|
|
@@ -68,11 +109,21 @@ export type SqlRuntimeAdapterInstance<TTargetId extends string = string> = Runti
|
|
|
68
109
|
// SQL Runtime Context
|
|
69
110
|
// ============================================================================
|
|
70
111
|
|
|
112
|
+
export type { TypeHelperRegistry };
|
|
113
|
+
|
|
71
114
|
export interface RuntimeContext<TContract extends SqlContract<SqlStorage> = SqlContract<SqlStorage>>
|
|
72
115
|
extends QueryLaneContext<TContract> {
|
|
73
116
|
readonly adapter:
|
|
74
117
|
| Adapter<QueryAst, TContract, LoweredStatement>
|
|
75
118
|
| Adapter<QueryAst, SqlContract<SqlStorage>, LoweredStatement>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Initialized type helpers from storage.types.
|
|
122
|
+
* Each entry corresponds to a named type instance in the contract's storage.types.
|
|
123
|
+
* The value is the result of calling the codec's init hook (if provided)
|
|
124
|
+
* or the validated typeParams (if no init hook).
|
|
125
|
+
*/
|
|
126
|
+
readonly types?: TypeHelperRegistry;
|
|
76
127
|
}
|
|
77
128
|
|
|
78
129
|
/**
|
|
@@ -96,6 +147,185 @@ export interface CreateRuntimeContextOptions<
|
|
|
96
147
|
readonly extensionPacks?: ReadonlyArray<SqlRuntimeExtensionDescriptor<TTargetId>>;
|
|
97
148
|
}
|
|
98
149
|
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// Runtime Error Types and Helpers
|
|
152
|
+
// ============================================================================
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Structured error thrown by the SQL runtime.
|
|
156
|
+
*
|
|
157
|
+
* Aligns with the repository's error envelope convention:
|
|
158
|
+
* - `code`: Stable error code for programmatic handling (e.g., `RUNTIME.TYPE_PARAMS_INVALID`)
|
|
159
|
+
* - `category`: Error source category (`RUNTIME`)
|
|
160
|
+
* - `severity`: Error severity level (`error`)
|
|
161
|
+
* - `details`: Optional structured details for debugging
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* try {
|
|
166
|
+
* createRuntimeContext({ ... });
|
|
167
|
+
* } catch (e) {
|
|
168
|
+
* if ((e as RuntimeError).code === 'RUNTIME.TYPE_PARAMS_INVALID') {
|
|
169
|
+
* console.error('Invalid type parameters:', (e as RuntimeError).details);
|
|
170
|
+
* }
|
|
171
|
+
* }
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export interface RuntimeError extends Error {
|
|
175
|
+
/** Stable error code for programmatic handling (e.g., `RUNTIME.TYPE_PARAMS_INVALID`) */
|
|
176
|
+
readonly code: string;
|
|
177
|
+
/** Error source category */
|
|
178
|
+
readonly category: 'RUNTIME';
|
|
179
|
+
/** Error severity level */
|
|
180
|
+
readonly severity: 'error';
|
|
181
|
+
/** Optional structured details for debugging */
|
|
182
|
+
readonly details?: Record<string, unknown>;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Creates a RuntimeError for invalid type parameters.
|
|
187
|
+
*
|
|
188
|
+
* Error code: `RUNTIME.TYPE_PARAMS_INVALID`
|
|
189
|
+
*
|
|
190
|
+
* Thrown when:
|
|
191
|
+
* - `storage.types` entries have typeParams that fail codec schema validation
|
|
192
|
+
* - Column inline typeParams fail codec schema validation
|
|
193
|
+
*
|
|
194
|
+
* @internal
|
|
195
|
+
*/
|
|
196
|
+
function runtimeTypeParamsInvalid(
|
|
197
|
+
message: string,
|
|
198
|
+
details?: Record<string, unknown>,
|
|
199
|
+
): RuntimeError {
|
|
200
|
+
const error = new Error(message) as RuntimeError;
|
|
201
|
+
Object.defineProperty(error, 'name', { value: 'RuntimeError', configurable: true });
|
|
202
|
+
return Object.assign(error, {
|
|
203
|
+
code: 'RUNTIME.TYPE_PARAMS_INVALID',
|
|
204
|
+
category: 'RUNTIME' as const,
|
|
205
|
+
severity: 'error' as const,
|
|
206
|
+
details,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ============================================================================
|
|
211
|
+
// Parameterized Type Validation
|
|
212
|
+
// ============================================================================
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Validates typeParams against the codec's paramsSchema.
|
|
216
|
+
* @throws RuntimeError with code RUNTIME.TYPE_PARAMS_INVALID if validation fails
|
|
217
|
+
*/
|
|
218
|
+
function validateTypeParams(
|
|
219
|
+
typeParams: Record<string, unknown>,
|
|
220
|
+
codecDescriptor: RuntimeParameterizedCodecDescriptor,
|
|
221
|
+
context: { typeName?: string; tableName?: string; columnName?: string },
|
|
222
|
+
): Record<string, unknown> {
|
|
223
|
+
const result = codecDescriptor.paramsSchema(typeParams);
|
|
224
|
+
if (result instanceof arktype.errors) {
|
|
225
|
+
const messages = result.map((p: { message: string }) => p.message).join('; ');
|
|
226
|
+
const locationInfo = context.typeName
|
|
227
|
+
? `type '${context.typeName}'`
|
|
228
|
+
: `column '${context.tableName}.${context.columnName}'`;
|
|
229
|
+
throw runtimeTypeParamsInvalid(
|
|
230
|
+
`Invalid typeParams for ${locationInfo} (codecId: ${codecDescriptor.codecId}): ${messages}`,
|
|
231
|
+
{ ...context, codecId: codecDescriptor.codecId, typeParams },
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return result as Record<string, unknown>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Collects parameterized codec descriptors from extension instances.
|
|
239
|
+
* Returns a map of codecId → descriptor for quick lookup.
|
|
240
|
+
*/
|
|
241
|
+
function collectParameterizedCodecDescriptors(
|
|
242
|
+
extensionInstances: ReadonlyArray<SqlRuntimeExtensionInstance<string>>,
|
|
243
|
+
): Map<string, RuntimeParameterizedCodecDescriptor> {
|
|
244
|
+
const descriptors = new Map<string, RuntimeParameterizedCodecDescriptor>();
|
|
245
|
+
|
|
246
|
+
for (const extInstance of extensionInstances) {
|
|
247
|
+
const paramCodecs = extInstance.parameterizedCodecs?.();
|
|
248
|
+
if (paramCodecs) {
|
|
249
|
+
for (const descriptor of paramCodecs) {
|
|
250
|
+
if (descriptors.has(descriptor.codecId)) {
|
|
251
|
+
console.warn(
|
|
252
|
+
`Duplicate parameterized codec descriptor for codecId '${descriptor.codecId}' - using later registration`,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
descriptors.set(descriptor.codecId, descriptor);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return descriptors;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Initializes type helpers from storage.types using codec descriptors.
|
|
265
|
+
*
|
|
266
|
+
* For each named type instance in `storage.types`:
|
|
267
|
+
* - If a codec descriptor exists with an `init` hook: calls the hook and stores the result
|
|
268
|
+
* - Otherwise: stores the full type instance metadata directly (codecId, nativeType, typeParams)
|
|
269
|
+
*
|
|
270
|
+
* This matches the typing in `ExtractSchemaTypes<Contract>` which extracts
|
|
271
|
+
* `Contract['storage']['types']` directly, ensuring runtime values match static types
|
|
272
|
+
* when no init hook transforms the value.
|
|
273
|
+
*/
|
|
274
|
+
function initializeTypeHelpers(
|
|
275
|
+
storageTypes: Record<string, StorageTypeInstance> | undefined,
|
|
276
|
+
codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
|
|
277
|
+
): TypeHelperRegistry {
|
|
278
|
+
const helpers: TypeHelperRegistry = {};
|
|
279
|
+
|
|
280
|
+
if (!storageTypes) {
|
|
281
|
+
return helpers;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
for (const [typeName, typeInstance] of Object.entries(storageTypes)) {
|
|
285
|
+
const descriptor = codecDescriptors.get(typeInstance.codecId);
|
|
286
|
+
|
|
287
|
+
if (descriptor) {
|
|
288
|
+
// Validate typeParams against the codec's schema
|
|
289
|
+
const validatedParams = validateTypeParams(typeInstance.typeParams, descriptor, {
|
|
290
|
+
typeName,
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// Call init hook if provided, otherwise store full type instance
|
|
294
|
+
if (descriptor.init) {
|
|
295
|
+
helpers[typeName] = descriptor.init(validatedParams);
|
|
296
|
+
} else {
|
|
297
|
+
// No init hook: expose full type instance metadata (matches contract typing)
|
|
298
|
+
helpers[typeName] = typeInstance;
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
// No descriptor found: expose full type instance (no validation possible)
|
|
302
|
+
helpers[typeName] = typeInstance;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return helpers;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Validates inline column typeParams across all tables.
|
|
311
|
+
* @throws RuntimeError with code RUNTIME.TYPE_PARAMS_INVALID if validation fails
|
|
312
|
+
*/
|
|
313
|
+
function validateColumnTypeParams(
|
|
314
|
+
storage: SqlStorage,
|
|
315
|
+
codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
|
|
316
|
+
): void {
|
|
317
|
+
for (const [tableName, table] of Object.entries(storage.tables)) {
|
|
318
|
+
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
319
|
+
if (column.typeParams) {
|
|
320
|
+
const descriptor = codecDescriptors.get(column.codecId);
|
|
321
|
+
if (descriptor) {
|
|
322
|
+
validateTypeParams(column.typeParams, descriptor, { tableName, columnName });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
99
329
|
/**
|
|
100
330
|
* Creates a SQL runtime context from descriptor-first composition.
|
|
101
331
|
*
|
|
@@ -104,6 +334,7 @@ export interface CreateRuntimeContextOptions<
|
|
|
104
334
|
* - The adapter instance (created from descriptor)
|
|
105
335
|
* - Codec registry (populated from adapter + extension instances)
|
|
106
336
|
* - Operation registry (populated from extension instances)
|
|
337
|
+
* - Types registry (initialized helpers from storage.types)
|
|
107
338
|
*
|
|
108
339
|
* @param options - Descriptor-first composition options
|
|
109
340
|
* @returns RuntimeContext with registries wired from all components
|
|
@@ -128,9 +359,12 @@ export function createRuntimeContext<
|
|
|
128
359
|
codecRegistry.register(codec);
|
|
129
360
|
}
|
|
130
361
|
|
|
131
|
-
// Create extension instances and
|
|
362
|
+
// Create extension instances and collect their contributions
|
|
363
|
+
const extensionInstances: SqlRuntimeExtensionInstance<TTargetId>[] = [];
|
|
364
|
+
|
|
132
365
|
for (const extDescriptor of extensionPacks ?? []) {
|
|
133
366
|
const extInstance = extDescriptor.create();
|
|
367
|
+
extensionInstances.push(extInstance);
|
|
134
368
|
|
|
135
369
|
const extCodecs = extInstance.codecs?.();
|
|
136
370
|
if (extCodecs) {
|
|
@@ -147,10 +381,22 @@ export function createRuntimeContext<
|
|
|
147
381
|
}
|
|
148
382
|
}
|
|
149
383
|
|
|
384
|
+
// Collect parameterized codec descriptors from extensions
|
|
385
|
+
const parameterizedCodecDescriptors = collectParameterizedCodecDescriptors(extensionInstances);
|
|
386
|
+
|
|
387
|
+
// Validate column typeParams if any descriptors are registered
|
|
388
|
+
if (parameterizedCodecDescriptors.size > 0) {
|
|
389
|
+
validateColumnTypeParams(contract.storage, parameterizedCodecDescriptors);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Initialize type helpers from storage.types
|
|
393
|
+
const types = initializeTypeHelpers(contract.storage.types, parameterizedCodecDescriptors);
|
|
394
|
+
|
|
150
395
|
return {
|
|
151
396
|
contract,
|
|
152
397
|
adapter: adapterInstance,
|
|
153
398
|
operations: operationRegistry,
|
|
154
399
|
codecs: codecRegistry,
|
|
400
|
+
types,
|
|
155
401
|
};
|
|
156
402
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { SqlContract, SqlMappings, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
2
|
+
import { expectTypeOf, test } from 'vitest';
|
|
3
|
+
import type { RuntimeContext, 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('RuntimeContext.types is TypeHelperRegistry', () => {
|
|
37
|
+
// RuntimeContext.types is intentionally loose (Record<string, unknown>)
|
|
38
|
+
// The strong typing comes from schema(context).types via ExtractSchemaTypes
|
|
39
|
+
expectTypeOf<RuntimeContext<TestContract>['types']>().toEqualTypeOf<
|
|
40
|
+
TypeHelperRegistry | undefined
|
|
41
|
+
>();
|
|
42
|
+
|
|
43
|
+
// TypeHelperRegistry allows any values - the actual type depends on init hooks
|
|
44
|
+
expectTypeOf<TypeHelperRegistry>().toEqualTypeOf<Record<string, unknown>>();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('RuntimeContext preserves contract type parameter', () => {
|
|
48
|
+
// Verify the contract type is preserved in RuntimeContext
|
|
49
|
+
expectTypeOf<RuntimeContext<TestContract>['contract']>().toEqualTypeOf<TestContract>();
|
|
50
|
+
|
|
51
|
+
// Verify we can access storage.types through the context's contract
|
|
52
|
+
type ContractStorageTypes = RuntimeContext<TestContract>['contract']['storage']['types'];
|
|
53
|
+
expectTypeOf<ContractStorageTypes>().toExtend<
|
|
54
|
+
| {
|
|
55
|
+
readonly Vector1536: {
|
|
56
|
+
readonly codecId: 'pg/vector@1';
|
|
57
|
+
readonly nativeType: 'vector';
|
|
58
|
+
readonly typeParams: { readonly length: 1536 };
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
| undefined
|
|
62
|
+
>();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('RuntimeContext accepts generic SqlContract', () => {
|
|
66
|
+
// Verify RuntimeContext defaults work
|
|
67
|
+
type DefaultContext = RuntimeContext;
|
|
68
|
+
expectTypeOf<DefaultContext['contract']>().toExtend<SqlContract<SqlStorage>>();
|
|
69
|
+
expectTypeOf<DefaultContext['types']>().toEqualTypeOf<TypeHelperRegistry | undefined>();
|
|
70
|
+
});
|