@prisma-next/sql-runtime 0.5.0-dev.30 → 0.5.0-dev.32
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/{exports-Cq_9ZrU4.mjs → exports-CrHMfIKo.mjs} +264 -55
- package/dist/exports-CrHMfIKo.mjs.map +1 -0
- package/dist/{index-Df2GsLSH.d.mts → index-_dXSGeho.d.mts} +15 -11
- package/dist/index-_dXSGeho.d.mts.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/test/utils.d.mts +1 -1
- package/dist/test/utils.mjs +1 -1
- package/package.json +9 -9
- package/src/codecs/decoding.ts +45 -7
- package/src/codecs/encoding.ts +47 -6
- package/src/codecs/validation.ts +22 -3
- package/src/sql-context.ts +332 -78
- package/src/sql-runtime.ts +14 -5
- package/dist/exports-Cq_9ZrU4.mjs.map +0 -1
- package/dist/index-Df2GsLSH.d.mts.map +0 -1
|
@@ -2,6 +2,7 @@ import { AsyncIterableResult, RuntimeCore, checkAborted, checkMiddlewareCompatib
|
|
|
2
2
|
import { type } from "arktype";
|
|
3
3
|
import { collectOrderedParamRefs, createCodecRegistry, isQueryAst } from "@prisma-next/sql-relational-core/ast";
|
|
4
4
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
5
|
+
import { synthesizeNonParameterizedDescriptor } from "@prisma-next/framework-components/codec";
|
|
5
6
|
import { checkContractComponentRequirements } from "@prisma-next/framework-components/components";
|
|
6
7
|
import { createExecutionStack } from "@prisma-next/framework-components/execution";
|
|
7
8
|
import { createSqlOperationRegistry } from "@prisma-next/sql-operations";
|
|
@@ -25,10 +26,17 @@ function extractCodecIdsFromColumns(contract) {
|
|
|
25
26
|
}
|
|
26
27
|
return codecIds;
|
|
27
28
|
}
|
|
29
|
+
function adaptDescriptorRegistry(registry) {
|
|
30
|
+
return { has: (id) => registry.descriptorFor(id) !== void 0 };
|
|
31
|
+
}
|
|
32
|
+
function isDescriptorRegistry(registry) {
|
|
33
|
+
return "descriptorFor" in registry;
|
|
34
|
+
}
|
|
28
35
|
function validateContractCodecMappings(registry, contract) {
|
|
36
|
+
const lookup = isDescriptorRegistry(registry) ? adaptDescriptorRegistry(registry) : registry;
|
|
29
37
|
const codecIds = extractCodecIdsFromColumns(contract);
|
|
30
38
|
const invalidCodecs = [];
|
|
31
|
-
for (const [key, codecId] of codecIds.entries()) if (!
|
|
39
|
+
for (const [key, codecId] of codecIds.entries()) if (!lookup.has(codecId)) {
|
|
32
40
|
const parts = key.split(".");
|
|
33
41
|
const table = parts[0] ?? "";
|
|
34
42
|
const column = parts[1] ?? "";
|
|
@@ -437,16 +445,21 @@ function assertExecutionStackContractRequirements(contract, stack) {
|
|
|
437
445
|
}
|
|
438
446
|
}
|
|
439
447
|
function validateTypeParams(typeParams, codecDescriptor, context) {
|
|
440
|
-
const result = codecDescriptor.paramsSchema(typeParams);
|
|
441
|
-
if (result instanceof
|
|
442
|
-
|
|
448
|
+
const result = codecDescriptor.paramsSchema["~standard"].validate(typeParams);
|
|
449
|
+
if (result instanceof Promise) throw runtimeError("RUNTIME.TYPE_PARAMS_INVALID", `paramsSchema for codec '${codecDescriptor.codecId}' returned a Promise; runtime validation requires a synchronous Standard Schema validator.`, {
|
|
450
|
+
...context,
|
|
451
|
+
codecId: codecDescriptor.codecId,
|
|
452
|
+
typeParams
|
|
453
|
+
});
|
|
454
|
+
if (result.issues) {
|
|
455
|
+
const messages = result.issues.map((issue) => issue.message).join("; ");
|
|
443
456
|
throw runtimeError("RUNTIME.TYPE_PARAMS_INVALID", `Invalid typeParams for ${context.typeName ? `type '${context.typeName}'` : `column '${context.tableName}.${context.columnName}'`} (codecId: ${codecDescriptor.codecId}): ${messages}`, {
|
|
444
457
|
...context,
|
|
445
458
|
codecId: codecDescriptor.codecId,
|
|
446
459
|
typeParams
|
|
447
460
|
});
|
|
448
461
|
}
|
|
449
|
-
return result;
|
|
462
|
+
return result.value;
|
|
450
463
|
}
|
|
451
464
|
function collectParameterizedCodecDescriptors(contributors) {
|
|
452
465
|
const descriptors = /* @__PURE__ */ new Map();
|
|
@@ -456,16 +469,76 @@ function collectParameterizedCodecDescriptors(contributors) {
|
|
|
456
469
|
}
|
|
457
470
|
return descriptors;
|
|
458
471
|
}
|
|
459
|
-
|
|
472
|
+
/**
|
|
473
|
+
* Build the unified descriptor map. Combines parameterized descriptors
|
|
474
|
+
* (which already ship as `CodecDescriptor`s) with synthesized descriptors
|
|
475
|
+
* for non-parameterized codecs registered through the legacy `codecs:`
|
|
476
|
+
* slot. Codec ids that ship a parameterized descriptor take precedence —
|
|
477
|
+
* even when the legacy registry registers a representative codec under
|
|
478
|
+
* the same id, the parameterized descriptor is the authoritative source.
|
|
479
|
+
*
|
|
480
|
+
* Codec-registry-unification spec § Decision: every codec resolves
|
|
481
|
+
* through one descriptor map; reads are non-branching.
|
|
482
|
+
*/
|
|
483
|
+
function buildCodecDescriptorRegistry(codecRegistry, parameterizedDescriptors) {
|
|
484
|
+
const byId = /* @__PURE__ */ new Map();
|
|
485
|
+
const byTargetType = /* @__PURE__ */ new Map();
|
|
486
|
+
function registerInIndices(descriptor) {
|
|
487
|
+
byId.set(descriptor.codecId, descriptor);
|
|
488
|
+
for (const targetType of descriptor.targetTypes) {
|
|
489
|
+
const list = byTargetType.get(targetType);
|
|
490
|
+
if (list) list.push(descriptor);
|
|
491
|
+
else byTargetType.set(targetType, [descriptor]);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
for (const descriptor of parameterizedDescriptors.values()) registerInIndices(descriptor);
|
|
495
|
+
for (const codec$1 of codecRegistry.values()) {
|
|
496
|
+
if (byId.has(codec$1.id)) continue;
|
|
497
|
+
registerInIndices(synthesizeNonParameterizedDescriptor(codec$1));
|
|
498
|
+
}
|
|
499
|
+
return {
|
|
500
|
+
descriptorFor(codecId) {
|
|
501
|
+
return byId.get(codecId);
|
|
502
|
+
},
|
|
503
|
+
*values() {
|
|
504
|
+
yield* byId.values();
|
|
505
|
+
},
|
|
506
|
+
byTargetType(targetType) {
|
|
507
|
+
return byTargetType.get(targetType) ?? Object.freeze([]);
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function collectTypeRefSites(storage) {
|
|
512
|
+
const sites = /* @__PURE__ */ new Map();
|
|
513
|
+
for (const [tableName, table] of Object.entries(storage.tables)) for (const [columnName, column] of Object.entries(table.columns)) {
|
|
514
|
+
if (typeof column.typeRef !== "string") continue;
|
|
515
|
+
const list = sites.get(column.typeRef);
|
|
516
|
+
const entry = {
|
|
517
|
+
table: tableName,
|
|
518
|
+
column: columnName
|
|
519
|
+
};
|
|
520
|
+
if (list) list.push(entry);
|
|
521
|
+
else sites.set(column.typeRef, [entry]);
|
|
522
|
+
}
|
|
523
|
+
return sites;
|
|
524
|
+
}
|
|
525
|
+
function initializeTypeHelpers(storage, codecDescriptors) {
|
|
460
526
|
const helpers = {};
|
|
527
|
+
const storageTypes = storage.types;
|
|
461
528
|
if (!storageTypes) return helpers;
|
|
529
|
+
const typeRefSites = collectTypeRefSites(storage);
|
|
462
530
|
for (const [typeName, typeInstance] of Object.entries(storageTypes)) {
|
|
463
531
|
const descriptor = codecDescriptors.get(typeInstance.codecId);
|
|
464
|
-
if (descriptor) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
532
|
+
if (!descriptor) {
|
|
533
|
+
helpers[typeName] = typeInstance;
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const validatedParams = validateTypeParams(typeInstance.typeParams, descriptor, { typeName });
|
|
537
|
+
const ctx = {
|
|
538
|
+
name: typeName,
|
|
539
|
+
usedAt: typeRefSites.get(typeName) ?? []
|
|
540
|
+
};
|
|
541
|
+
helpers[typeName] = descriptor.factory(validatedParams)(ctx);
|
|
469
542
|
}
|
|
470
543
|
return helpers;
|
|
471
544
|
}
|
|
@@ -478,39 +551,115 @@ function validateColumnTypeParams(storage, codecDescriptors) {
|
|
|
478
551
|
});
|
|
479
552
|
}
|
|
480
553
|
}
|
|
554
|
+
function hasJsonValidatorTrait(candidate) {
|
|
555
|
+
if (candidate === null || typeof candidate !== "object") return false;
|
|
556
|
+
const traits = candidate.traits;
|
|
557
|
+
if (!Array.isArray(traits)) return false;
|
|
558
|
+
if (!traits.includes("json-validator")) return false;
|
|
559
|
+
return typeof candidate.validate === "function";
|
|
560
|
+
}
|
|
561
|
+
function extractValidator(candidate) {
|
|
562
|
+
return hasJsonValidatorTrait(candidate) ? candidate.validate : void 0;
|
|
563
|
+
}
|
|
564
|
+
function isResolvedCodec(candidate) {
|
|
565
|
+
return candidate !== null && typeof candidate === "object" && "id" in candidate && "decode" in candidate;
|
|
566
|
+
}
|
|
481
567
|
/**
|
|
482
|
-
*
|
|
483
|
-
*
|
|
568
|
+
* Walk the contract's `storage.tables[].columns[]` and resolve each
|
|
569
|
+
* column to a `Codec` through the unified descriptor map. Per-instance
|
|
570
|
+
* behavior:
|
|
484
571
|
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
572
|
+
* - **typeRef columns**: reuse the resolved codec materialized once by
|
|
573
|
+
* `initializeTypeHelpers` for the `storage.types` entry. Multiple
|
|
574
|
+
* columns sharing one typeRef share one codec instance.
|
|
575
|
+
* - **inline-typeParams columns**: call `descriptor.factory(typeParams)
|
|
576
|
+
* (ctx)` once per column (per-column anonymous instance).
|
|
577
|
+
* - **non-parameterized columns**: call `descriptor.factory()(ctx)`
|
|
578
|
+
* once. The synthesized descriptor's factory is constant — every call
|
|
579
|
+
* returns the same shared codec instance — so columns sharing a non-
|
|
580
|
+
* parameterized codec id share one resolved codec without explicit
|
|
581
|
+
* caching.
|
|
582
|
+
*
|
|
583
|
+
* Combines what `initializeTypeHelpers` (named-instance walk) and the
|
|
584
|
+
* old `buildJsonSchemaValidatorRegistry` (per-column walk) used to do
|
|
585
|
+
* separately: one walk over all columns, one resolved codec per column,
|
|
586
|
+
* one trait-gated validator extraction per column. The result drives
|
|
587
|
+
* both the dispatch registry (`ContractCodecRegistry.forColumn`) and the
|
|
588
|
+
* validator registry.
|
|
589
|
+
*
|
|
590
|
+
* Codec-registry-unification spec § AC-4: every column resolves through
|
|
591
|
+
* one descriptor map without branching on parameterization.
|
|
488
592
|
*/
|
|
489
|
-
function
|
|
593
|
+
function buildContractCodecRegistry(contract, codecDescriptors, legacyCodecRegistry, types, parameterizedDescriptors) {
|
|
594
|
+
const byColumn = /* @__PURE__ */ new Map();
|
|
595
|
+
const byCodecId = /* @__PURE__ */ new Map();
|
|
596
|
+
const ambiguousCodecIds = /* @__PURE__ */ new Set();
|
|
490
597
|
const validators = /* @__PURE__ */ new Map();
|
|
491
|
-
const codecIdsWithInit = /* @__PURE__ */ new Set();
|
|
492
|
-
for (const [codecId, descriptor] of codecDescriptors) if (descriptor.init) codecIdsWithInit.add(codecId);
|
|
493
|
-
if (codecIdsWithInit.size === 0) return;
|
|
494
598
|
for (const [tableName, table] of Object.entries(contract.storage.tables)) for (const [columnName, column] of Object.entries(table.columns)) {
|
|
495
|
-
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
599
|
+
const columnKey = `${tableName}.${columnName}`;
|
|
600
|
+
const descriptor = codecDescriptors.descriptorFor(column.codecId);
|
|
601
|
+
let resolvedCodec;
|
|
602
|
+
if (descriptor) {
|
|
603
|
+
const isParameterized = parameterizedDescriptors.has(column.codecId);
|
|
604
|
+
if (column.typeRef) {
|
|
605
|
+
const helper = types[column.typeRef];
|
|
606
|
+
if (isResolvedCodec(helper)) resolvedCodec = helper;
|
|
607
|
+
} else if (column.typeParams && isParameterized) {
|
|
608
|
+
const parameterizedDescriptor = parameterizedDescriptors.get(column.codecId);
|
|
609
|
+
if (parameterizedDescriptor) {
|
|
610
|
+
const validatedParams = validateTypeParams(column.typeParams, parameterizedDescriptor, {
|
|
611
|
+
tableName,
|
|
612
|
+
columnName
|
|
613
|
+
});
|
|
614
|
+
const ctx = {
|
|
615
|
+
name: `<anon:${tableName}.${columnName}>`,
|
|
616
|
+
usedAt: [{
|
|
617
|
+
table: tableName,
|
|
618
|
+
column: columnName
|
|
619
|
+
}]
|
|
620
|
+
};
|
|
621
|
+
resolvedCodec = parameterizedDescriptor.factory(validatedParams)(ctx);
|
|
622
|
+
}
|
|
623
|
+
} else if (!isParameterized) {
|
|
624
|
+
let cached = byCodecId.get(column.codecId);
|
|
625
|
+
if (!cached) {
|
|
626
|
+
const ctx = {
|
|
627
|
+
name: `<shared:${column.codecId}>`,
|
|
628
|
+
usedAt: [{
|
|
629
|
+
table: tableName,
|
|
630
|
+
column: columnName
|
|
631
|
+
}]
|
|
632
|
+
};
|
|
633
|
+
const voidFactory = descriptor.factory;
|
|
634
|
+
cached = voidFactory(void 0)(ctx);
|
|
635
|
+
byCodecId.set(column.codecId, cached);
|
|
636
|
+
}
|
|
637
|
+
resolvedCodec = cached;
|
|
507
638
|
}
|
|
508
639
|
}
|
|
640
|
+
if (resolvedCodec) {
|
|
641
|
+
byColumn.set(columnKey, resolvedCodec);
|
|
642
|
+
const validate = extractValidator(resolvedCodec);
|
|
643
|
+
if (validate) validators.set(columnKey, validate);
|
|
644
|
+
const existing = byCodecId.get(column.codecId);
|
|
645
|
+
if (existing === void 0) byCodecId.set(column.codecId, resolvedCodec);
|
|
646
|
+
else if (existing !== resolvedCodec && parameterizedDescriptors.has(column.codecId)) ambiguousCodecIds.add(column.codecId);
|
|
647
|
+
}
|
|
509
648
|
}
|
|
510
|
-
if (validators.size === 0) return void 0;
|
|
511
649
|
return {
|
|
512
|
-
|
|
513
|
-
|
|
650
|
+
registry: {
|
|
651
|
+
forColumn(table, column) {
|
|
652
|
+
return byColumn.get(`${table}.${column}`);
|
|
653
|
+
},
|
|
654
|
+
forCodecId(codecId) {
|
|
655
|
+
if (ambiguousCodecIds.has(codecId)) throw runtimeError("RUNTIME.TYPE_PARAMS_INVALID", `Codec '${codecId}' resolves to multiple parameterized instances; column-aware dispatch is required.`, { codecId });
|
|
656
|
+
return byCodecId.get(codecId) ?? legacyCodecRegistry.get(codecId);
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
jsonValidators: validators.size > 0 ? {
|
|
660
|
+
get: (key) => validators.get(key),
|
|
661
|
+
size: validators.size
|
|
662
|
+
} : void 0
|
|
514
663
|
};
|
|
515
664
|
}
|
|
516
665
|
function collectMutationDefaultGenerators(contributors) {
|
|
@@ -572,13 +721,16 @@ function createExecutionContext(options) {
|
|
|
572
721
|
const queryOperationRegistry = createSqlOperationRegistry();
|
|
573
722
|
for (const contributor of contributors) for (const op of contributor.queryOperations?.() ?? []) queryOperationRegistry.register(op);
|
|
574
723
|
const parameterizedCodecDescriptors = collectParameterizedCodecDescriptors(contributors);
|
|
724
|
+
const codecDescriptors = buildCodecDescriptorRegistry(codecRegistry, parameterizedCodecDescriptors);
|
|
575
725
|
const mutationDefaultGeneratorRegistry = collectMutationDefaultGenerators(contributors);
|
|
576
726
|
if (parameterizedCodecDescriptors.size > 0) validateColumnTypeParams(contract.storage, parameterizedCodecDescriptors);
|
|
577
|
-
const types = initializeTypeHelpers(contract.storage
|
|
578
|
-
const jsonSchemaValidators =
|
|
727
|
+
const types = initializeTypeHelpers(contract.storage, parameterizedCodecDescriptors);
|
|
728
|
+
const { registry: contractCodecs, jsonValidators: jsonSchemaValidators } = buildContractCodecRegistry(contract, codecDescriptors, codecRegistry, types, parameterizedCodecDescriptors);
|
|
579
729
|
return {
|
|
580
730
|
contract,
|
|
581
731
|
codecs: codecRegistry,
|
|
732
|
+
contractCodecs,
|
|
733
|
+
codecDescriptors,
|
|
582
734
|
queryOperations: queryOperationRegistry,
|
|
583
735
|
types,
|
|
584
736
|
...jsonSchemaValidators ? { jsonSchemaValidators } : {},
|
|
@@ -740,7 +892,35 @@ function projectionListFromAst(ast) {
|
|
|
740
892
|
if (ast.kind === "select") return ast.projection;
|
|
741
893
|
return ast.returning;
|
|
742
894
|
}
|
|
743
|
-
|
|
895
|
+
/**
|
|
896
|
+
* Resolve the per-cell codec for a projection item.
|
|
897
|
+
*
|
|
898
|
+
* Phase B: when a `(table, column)` ref is available for the projection,
|
|
899
|
+
* prefer `contractCodecs.forColumn(table, column)` — that's the per-
|
|
900
|
+
* instance resolved codec materialized from the codec descriptor's
|
|
901
|
+
* factory at context-construction time (carries any per-instance state
|
|
902
|
+
* such as the compiled JSON-Schema validator). When the projection
|
|
903
|
+
* resolves to a non-`column-ref` expression (computed projections, raw
|
|
904
|
+
* SQL aliases) but still carries a codec id (ADR 205 stamps every
|
|
905
|
+
* `ProjectionItem` with the producer's codec id), fall back to the
|
|
906
|
+
* codec-id-keyed `forCodecId(codecId)` lookup, which itself falls back
|
|
907
|
+
* to the legacy `CodecRegistry` for codec ids the contract walk
|
|
908
|
+
* couldn't resolve.
|
|
909
|
+
*
|
|
910
|
+
* Codec-registry-unification spec § AC-4.
|
|
911
|
+
*/
|
|
912
|
+
function resolveProjectionCodec(item, registry, contractCodecs) {
|
|
913
|
+
if (item.expr.kind === "column-ref" && contractCodecs) {
|
|
914
|
+
const byColumn = contractCodecs.forColumn(item.expr.table, item.expr.column);
|
|
915
|
+
if (byColumn) return byColumn;
|
|
916
|
+
}
|
|
917
|
+
if (item.codecId) {
|
|
918
|
+
const fromContract = contractCodecs?.forCodecId(item.codecId);
|
|
919
|
+
if (fromContract) return fromContract;
|
|
920
|
+
return registry.get(item.codecId);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
function buildDecodeContext(plan, registry, contractCodecs) {
|
|
744
924
|
if (!isAstBackedPlan(plan)) return {
|
|
745
925
|
aliases: void 0,
|
|
746
926
|
codecs: /* @__PURE__ */ new Map(),
|
|
@@ -760,10 +940,8 @@ function buildDecodeContext(plan, registry) {
|
|
|
760
940
|
const includeAliases = /* @__PURE__ */ new Set();
|
|
761
941
|
for (const item of projection) {
|
|
762
942
|
aliases.push(item.alias);
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if (codec$1) codecs.set(item.alias, codec$1);
|
|
766
|
-
}
|
|
943
|
+
const codec$1 = resolveProjectionCodec(item, registry, contractCodecs);
|
|
944
|
+
if (codec$1) codecs.set(item.alias, codec$1);
|
|
767
945
|
if (item.expr.kind === "column-ref") columnRefs.set(item.alias, {
|
|
768
946
|
table: item.expr.table,
|
|
769
947
|
column: item.expr.column
|
|
@@ -882,10 +1060,10 @@ async function decodeField(alias, wireValue, decodeCtx, jsonValidators, rowCtx)
|
|
|
882
1060
|
* - Existing `RUNTIME.DECODE_FAILED` envelopes from codec bodies pass
|
|
883
1061
|
* through unchanged (no double wrap).
|
|
884
1062
|
*/
|
|
885
|
-
async function decodeRow(row, plan, registry, jsonValidators, rowCtx) {
|
|
1063
|
+
async function decodeRow(row, plan, registry, jsonValidators, rowCtx, contractCodecs) {
|
|
886
1064
|
checkAborted(rowCtx, "decode");
|
|
887
1065
|
const signal = rowCtx.signal;
|
|
888
|
-
const decodeCtx = buildDecodeContext(plan, registry);
|
|
1066
|
+
const decodeCtx = buildDecodeContext(plan, registry, contractCodecs);
|
|
889
1067
|
const aliases = decodeCtx.aliases ?? Object.keys(row);
|
|
890
1068
|
if (decodeCtx.aliases !== void 0) {
|
|
891
1069
|
for (const alias of decodeCtx.aliases) if (!Object.hasOwn(row, alias)) throw runtimeError("RUNTIME.DECODE_FAILED", `Row missing projection alias "${alias}"`, {
|
|
@@ -923,6 +1101,34 @@ const NO_METADATA = Object.freeze({
|
|
|
923
1101
|
codecId: void 0,
|
|
924
1102
|
name: void 0
|
|
925
1103
|
});
|
|
1104
|
+
/**
|
|
1105
|
+
* Resolve the codec for an outgoing param.
|
|
1106
|
+
*
|
|
1107
|
+
* Phase B (and AC-5-deferred carve-out): `ParamRef` does not carry a
|
|
1108
|
+
* `(table, column)` ref today — every `ParamRef` carries `codecId` but
|
|
1109
|
+
* not the column it relates to. Encode-side dispatch therefore consults
|
|
1110
|
+
* `contractCodecs.forCodecId(codecId)` (which itself prefers the
|
|
1111
|
+
* contract-walk-derived shared codec, falling back to the legacy
|
|
1112
|
+
* `CodecRegistry.get` for parameterized codec ids whose contracts don't
|
|
1113
|
+
* have a column the walk could resolve through).
|
|
1114
|
+
*
|
|
1115
|
+
* For the parameterized codecs shipped at Phase B (pgvector, postgres
|
|
1116
|
+
* json/jsonb), encode is per-instance-stateless w.r.t. params:
|
|
1117
|
+
* - pgvector formats `[v1,v2,...]` regardless of declared length;
|
|
1118
|
+
* - postgres json/jsonb encode is `JSON.stringify` regardless of schema.
|
|
1119
|
+
*
|
|
1120
|
+
* So the codec-id-keyed lookup yields a structurally equivalent encoder
|
|
1121
|
+
* even when the resolved per-instance codec carries extra state (e.g. a
|
|
1122
|
+
* compiled JSON-Schema validator used only by `decode`). TML-2357 retires
|
|
1123
|
+
* the fallback by threading `ParamRef.refs` through column-bound
|
|
1124
|
+
* construction sites.
|
|
1125
|
+
*/
|
|
1126
|
+
function resolveParamCodec(metadata, registry, contractCodecs) {
|
|
1127
|
+
if (!metadata.codecId) return void 0;
|
|
1128
|
+
const fromContract = contractCodecs?.forCodecId(metadata.codecId);
|
|
1129
|
+
if (fromContract) return fromContract;
|
|
1130
|
+
return registry.get(metadata.codecId);
|
|
1131
|
+
}
|
|
926
1132
|
function paramLabel(metadata, paramIndex) {
|
|
927
1133
|
return metadata.name ?? `param[${paramIndex}]`;
|
|
928
1134
|
}
|
|
@@ -936,10 +1142,9 @@ function wrapEncodeFailure(error, metadata, paramIndex, codecId) {
|
|
|
936
1142
|
wrapped.cause = error;
|
|
937
1143
|
throw wrapped;
|
|
938
1144
|
}
|
|
939
|
-
async function encodeParamValue(value, metadata, paramIndex, registry, ctx) {
|
|
1145
|
+
async function encodeParamValue(value, metadata, paramIndex, registry, ctx, contractCodecs) {
|
|
940
1146
|
if (value === null || value === void 0) return null;
|
|
941
|
-
|
|
942
|
-
const codec$1 = registry.get(metadata.codecId);
|
|
1147
|
+
const codec$1 = resolveParamCodec(metadata, registry, contractCodecs);
|
|
943
1148
|
if (!codec$1) return value;
|
|
944
1149
|
try {
|
|
945
1150
|
return await codec$1.encode(value, ctx);
|
|
@@ -966,7 +1171,7 @@ async function encodeParamValue(value, metadata, paramIndex, registry, ctx) {
|
|
|
966
1171
|
* body before the runtime observes the abort pass through unchanged
|
|
967
1172
|
* (no double wrap).
|
|
968
1173
|
*/
|
|
969
|
-
async function encodeParams(plan, registry, ctx) {
|
|
1174
|
+
async function encodeParams(plan, registry, ctx, contractCodecs) {
|
|
970
1175
|
checkAborted(ctx, "encode");
|
|
971
1176
|
const signal = ctx.signal;
|
|
972
1177
|
if (plan.params.length === 0) return plan.params;
|
|
@@ -983,7 +1188,7 @@ async function encodeParams(plan, registry, ctx) {
|
|
|
983
1188
|
}
|
|
984
1189
|
}
|
|
985
1190
|
const tasks = new Array(paramCount);
|
|
986
|
-
for (let i = 0; i < paramCount; i++) tasks[i] = encodeParamValue(plan.params[i], metadata[i] ?? NO_METADATA, i, registry, ctx);
|
|
1191
|
+
for (let i = 0; i < paramCount; i++) tasks[i] = encodeParamValue(plan.params[i], metadata[i] ?? NO_METADATA, i, registry, ctx, contractCodecs);
|
|
987
1192
|
const settled = await raceAgainstAbort(Promise.all(tasks), signal, "encode");
|
|
988
1193
|
return Object.freeze(settled);
|
|
989
1194
|
}
|
|
@@ -1057,6 +1262,8 @@ var SqlRuntimeImpl = class extends RuntimeCore {
|
|
|
1057
1262
|
driver;
|
|
1058
1263
|
familyAdapter;
|
|
1059
1264
|
codecRegistry;
|
|
1265
|
+
contractCodecs;
|
|
1266
|
+
codecDescriptors;
|
|
1060
1267
|
jsonSchemaValidators;
|
|
1061
1268
|
sqlCtx;
|
|
1062
1269
|
verify;
|
|
@@ -1086,6 +1293,8 @@ var SqlRuntimeImpl = class extends RuntimeCore {
|
|
|
1086
1293
|
this.driver = driver;
|
|
1087
1294
|
this.familyAdapter = new SqlFamilyAdapter(context.contract, adapter.profile);
|
|
1088
1295
|
this.codecRegistry = context.codecs;
|
|
1296
|
+
this.contractCodecs = context.contractCodecs;
|
|
1297
|
+
this.codecDescriptors = context.codecDescriptors;
|
|
1089
1298
|
this.jsonSchemaValidators = context.jsonSchemaValidators;
|
|
1090
1299
|
this.sqlCtx = sqlCtx;
|
|
1091
1300
|
this.verify = verify;
|
|
@@ -1094,7 +1303,7 @@ var SqlRuntimeImpl = class extends RuntimeCore {
|
|
|
1094
1303
|
this.startupVerified = false;
|
|
1095
1304
|
this._telemetry = null;
|
|
1096
1305
|
if (verify.mode === "startup") {
|
|
1097
|
-
validateCodecRegistryCompleteness(this.
|
|
1306
|
+
validateCodecRegistryCompleteness(this.codecDescriptors, context.contract);
|
|
1098
1307
|
this.codecRegistryValidated = true;
|
|
1099
1308
|
}
|
|
1100
1309
|
}
|
|
@@ -1113,7 +1322,7 @@ var SqlRuntimeImpl = class extends RuntimeCore {
|
|
|
1113
1322
|
const lowered = lowerSqlPlan(this.adapter, this.contract, plan);
|
|
1114
1323
|
return Object.freeze({
|
|
1115
1324
|
...lowered,
|
|
1116
|
-
params: await encodeParams(lowered, this.codecRegistry, ctx)
|
|
1325
|
+
params: await encodeParams(lowered, this.codecRegistry, ctx, this.contractCodecs)
|
|
1117
1326
|
});
|
|
1118
1327
|
}
|
|
1119
1328
|
/**
|
|
@@ -1160,7 +1369,7 @@ var SqlRuntimeImpl = class extends RuntimeCore {
|
|
|
1160
1369
|
checkAborted(codecCtx, "stream");
|
|
1161
1370
|
const exec = isExecutionPlan(plan) ? Object.freeze({
|
|
1162
1371
|
...plan,
|
|
1163
|
-
params: await encodeParams(plan, self.codecRegistry, codecCtx)
|
|
1372
|
+
params: await encodeParams(plan, self.codecRegistry, codecCtx, self.contractCodecs)
|
|
1164
1373
|
}) : await self.lower(await self.runBeforeCompile(plan), codecCtx);
|
|
1165
1374
|
self.familyAdapter.validatePlan(exec, self.contract);
|
|
1166
1375
|
self._telemetry = null;
|
|
@@ -1179,7 +1388,7 @@ var SqlRuntimeImpl = class extends RuntimeCore {
|
|
|
1179
1388
|
checkAborted(codecCtx, "stream");
|
|
1180
1389
|
const next = await iterator.next();
|
|
1181
1390
|
if (next.done) break;
|
|
1182
|
-
yield await decodeRow(next.value, exec, self.codecRegistry, self.jsonSchemaValidators, codecCtx);
|
|
1391
|
+
yield await decodeRow(next.value, exec, self.codecRegistry, self.jsonSchemaValidators, codecCtx, self.contractCodecs);
|
|
1183
1392
|
}
|
|
1184
1393
|
} finally {
|
|
1185
1394
|
await iterator.return?.();
|
|
@@ -1235,7 +1444,7 @@ var SqlRuntimeImpl = class extends RuntimeCore {
|
|
|
1235
1444
|
}
|
|
1236
1445
|
ensureCodecRegistryValidated() {
|
|
1237
1446
|
if (!this.codecRegistryValidated) {
|
|
1238
|
-
validateCodecRegistryCompleteness(this.
|
|
1447
|
+
validateCodecRegistryCompleteness(this.codecDescriptors, this.contract);
|
|
1239
1448
|
this.codecRegistryValidated = true;
|
|
1240
1449
|
}
|
|
1241
1450
|
}
|
|
@@ -1352,4 +1561,4 @@ function createRuntime(options) {
|
|
|
1352
1561
|
|
|
1353
1562
|
//#endregion
|
|
1354
1563
|
export { readContractMarker as a, createSqlExecutionStack as c, parseContractMarkerRow as d, lowerSqlPlan as f, validateContractCodecMappings as h, ensureTableStatement as i, lints as l, validateCodecRegistryCompleteness as m, withTransaction as n, writeContractMarker as o, extractCodecIds as p, ensureSchemaStatement as r, createExecutionContext as s, createRuntime as t, budgets as u };
|
|
1355
|
-
//# sourceMappingURL=exports-
|
|
1564
|
+
//# sourceMappingURL=exports-CrHMfIKo.mjs.map
|