@prisma-next/sql-runtime 0.12.0-dev.9 → 0.13.0-dev.1
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 +7 -4
- package/dist/{exports-CXYd2w6k.mjs → exports-DDqF-xmg.mjs} +158 -305
- package/dist/exports-DDqF-xmg.mjs.map +1 -0
- package/dist/{index-DTr7KoUs.d.mts → index-JOQlRa75.d.mts} +24 -59
- package/dist/index-JOQlRa75.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/test/utils.d.mts +28 -18
- package/dist/test/utils.d.mts.map +1 -1
- package/dist/test/utils.mjs +34 -28
- package/dist/test/utils.mjs.map +1 -1
- package/package.json +15 -15
- package/src/codecs/ast-codec-registry.ts +25 -0
- package/src/codecs/validation.ts +2 -2
- package/src/exports/index.ts +3 -10
- package/src/sql-context.ts +50 -33
- package/src/sql-runtime.ts +19 -20
- package/dist/exports-CXYd2w6k.mjs.map +0 -1
- package/dist/index-DTr7KoUs.d.mts.map +0 -1
- package/src/marker.ts +0 -75
- package/src/sql-marker.ts +0 -143
package/src/sql-context.ts
CHANGED
|
@@ -30,19 +30,10 @@ import { canonicalizeJson } from '@prisma-next/framework-components/utils';
|
|
|
30
30
|
import {
|
|
31
31
|
isPostgresEnumStorageEntry,
|
|
32
32
|
type SqlStorage,
|
|
33
|
-
type StorageTable,
|
|
34
33
|
type StorageTypeInstance,
|
|
35
34
|
} from '@prisma-next/sql-contract/types';
|
|
36
35
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
37
36
|
|
|
38
|
-
// Framework `Namespace.tables` is widened to `Record<string, object>` so
|
|
39
|
-
// emitted `contract.d.ts` table literals satisfy it structurally. At
|
|
40
|
-
// runtime, every `SqlStorage` namespace holds `StorageTable` instances —
|
|
41
|
-
// the constructor enforces it. Narrowing per-iteration with a single-step
|
|
42
|
-
// cast (not `as unknown as`) keeps Pattern C walks readable without
|
|
43
|
-
// weakening the substrate type.
|
|
44
|
-
type SqlNamespaceTables = Readonly<Record<string, StorageTable>>;
|
|
45
|
-
|
|
46
37
|
function documentScopedCodecTypes(
|
|
47
38
|
contract: Contract<SqlStorage>,
|
|
48
39
|
): Record<string, StorageTypeInstance> | undefined {
|
|
@@ -344,7 +335,7 @@ function collectTypeRefSites(
|
|
|
344
335
|
): Map<string, Array<{ readonly table: string; readonly column: string }>> {
|
|
345
336
|
const sites = new Map<string, Array<{ readonly table: string; readonly column: string }>>();
|
|
346
337
|
for (const ns of Object.values(storage.namespaces)) {
|
|
347
|
-
for (const [tableName, table] of Object.entries(ns.
|
|
338
|
+
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
348
339
|
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
349
340
|
if (typeof column.typeRef !== 'string') continue;
|
|
350
341
|
const list = sites.get(column.typeRef);
|
|
@@ -387,7 +378,9 @@ function initializeTypeHelpers(
|
|
|
387
378
|
continue;
|
|
388
379
|
}
|
|
389
380
|
|
|
390
|
-
|
|
381
|
+
// `typeParams` may be absent on the canonical empty form. Forward `{}`
|
|
382
|
+
// to the descriptor's paramsSchema so it can probe its own optionality.
|
|
383
|
+
const validatedParams = validateTypeParams(typeParams ?? {}, descriptor, {
|
|
391
384
|
typeName,
|
|
392
385
|
});
|
|
393
386
|
|
|
@@ -404,7 +397,7 @@ function validateColumnTypeParams(
|
|
|
404
397
|
codecDescriptors: Map<string, RuntimeParameterizedCodecDescriptor>,
|
|
405
398
|
): void {
|
|
406
399
|
for (const ns of Object.values(storage.namespaces)) {
|
|
407
|
-
for (const [tableName, table] of Object.entries(ns.
|
|
400
|
+
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
408
401
|
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
409
402
|
if (column.typeParams) {
|
|
410
403
|
const descriptor = codecDescriptors.get(column.codecId);
|
|
@@ -432,10 +425,10 @@ function assertColumnCodecIntegrity(
|
|
|
432
425
|
storage: SqlStorage,
|
|
433
426
|
codecDescriptors: CodecDescriptorRegistry,
|
|
434
427
|
): void {
|
|
435
|
-
for (const ns of Object.
|
|
436
|
-
for (const [tableName, table] of Object.entries(ns.
|
|
428
|
+
for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {
|
|
429
|
+
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
437
430
|
for (const columnName of Object.keys(table.columns)) {
|
|
438
|
-
const ref = codecDescriptors.codecRefForColumn(tableName, columnName);
|
|
431
|
+
const ref = codecDescriptors.codecRefForColumn(namespaceId, tableName, columnName);
|
|
439
432
|
if (!ref) continue;
|
|
440
433
|
|
|
441
434
|
const descriptor = codecDescriptors.descriptorFor(ref.codecId);
|
|
@@ -480,7 +473,22 @@ function assertColumnCodecIntegrity(
|
|
|
480
473
|
}
|
|
481
474
|
}
|
|
482
475
|
|
|
483
|
-
|
|
476
|
+
// An object-typed field's empty state is canonical at every boundary
|
|
477
|
+
// that compares them: `typeParams: {}` and missing `typeParams` are
|
|
478
|
+
// equivalent — both mean "no parameters were supplied". A
|
|
479
|
+
// non-parameterized codec only conflicts with typeParams that carry
|
|
480
|
+
// at least one key. The PSL interpreter emits `typeParams: {}` for
|
|
481
|
+
// `@db.X` named types whose body has no parameters; treating that as
|
|
482
|
+
// a mismatch would reject every such alias against `pg/text@1`
|
|
483
|
+
// (e.g. the supabase extension's `Uuid` type).
|
|
484
|
+
const refTypeParams = ref.typeParams;
|
|
485
|
+
const refHasTypeParamKeys =
|
|
486
|
+
refTypeParams !== undefined &&
|
|
487
|
+
refTypeParams !== null &&
|
|
488
|
+
typeof refTypeParams === 'object' &&
|
|
489
|
+
!Array.isArray(refTypeParams) &&
|
|
490
|
+
Object.keys(refTypeParams).length > 0;
|
|
491
|
+
if (!descriptor.isParameterized && refHasTypeParamKeys) {
|
|
484
492
|
throw runtimeError(
|
|
485
493
|
'RUNTIME.CODEC_PARAMETERIZATION_MISMATCH',
|
|
486
494
|
`Column '${tableName}.${columnName}' supplies typeParams to non-parameterized codec '${ref.codecId}'. Remove the typeParams or switch to a parameterized codec id.`,
|
|
@@ -512,7 +520,7 @@ function assertColumnCodecIntegrity(
|
|
|
512
520
|
*
|
|
513
521
|
* Contract integrity is enforced upstream by {@link assertColumnCodecIntegrity}: every column must reference a registered `codecId` whose `descriptor.isParameterized` flag matches the presence of `typeParams` (via `codecRefForColumn`). The pre-population walk and `forColumn` therefore make no defensive checks — malformed columns fail fast at `createExecutionContext` construction with `RUNTIME.CODEC_DESCRIPTOR_MISSING` or `RUNTIME.CODEC_PARAMETERIZATION_MISMATCH` rather than being silently skipped here.
|
|
514
522
|
*
|
|
515
|
-
* `forColumn(t, c)` is a thin delegate over `forCodecRef(codecRefForColumn(t, c))`; encode/decode hot paths read the resolver directly via `forCodecRef`. The only `undefined` `forColumn` returns is the legitimate "no such column in the contract" case.
|
|
523
|
+
* `forColumn(ns, t, c)` is a thin delegate over `forCodecRef(codecRefForColumn(ns, t, c))`; encode/decode hot paths read the resolver directly via `forCodecRef`. The only `undefined` `forColumn` returns is the legitimate "no such column in the contract" case.
|
|
516
524
|
*/
|
|
517
525
|
function buildContractCodecRegistry(
|
|
518
526
|
contract: Contract<SqlStorage>,
|
|
@@ -526,15 +534,24 @@ function buildContractCodecRegistry(
|
|
|
526
534
|
const typeRefSites = collectTypeRefSites(contract.storage);
|
|
527
535
|
for (const [typeName, typeInstance] of Object.entries(documentScopedCodecTypes(contract) ?? {})) {
|
|
528
536
|
const enumView = readEnumViewIfApplicable(typeInstance);
|
|
537
|
+
const instanceTypeParams = enumView
|
|
538
|
+
? enumView.typeParams
|
|
539
|
+
: (typeInstance as StorageTypeInstance).typeParams;
|
|
540
|
+
const hasParamKeys =
|
|
541
|
+
instanceTypeParams !== undefined && Object.keys(instanceTypeParams).length > 0;
|
|
529
542
|
const ref: CodecRef = enumView
|
|
530
|
-
?
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
543
|
+
? hasParamKeys
|
|
544
|
+
? {
|
|
545
|
+
codecId: enumView.codecId,
|
|
546
|
+
typeParams: instanceTypeParams as unknown as JsonValue,
|
|
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 };
|
|
538
555
|
const key = refKeyOf(ref);
|
|
539
556
|
const sites = typeRefSites.get(typeName) ?? [];
|
|
540
557
|
const existing = usedAtByKey.get(key);
|
|
@@ -547,11 +564,11 @@ function buildContractCodecRegistry(
|
|
|
547
564
|
}
|
|
548
565
|
}
|
|
549
566
|
|
|
550
|
-
for (const ns of Object.
|
|
551
|
-
for (const [tableName, table] of Object.entries(ns.
|
|
567
|
+
for (const [namespaceId, ns] of Object.entries(contract.storage.namespaces)) {
|
|
568
|
+
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
552
569
|
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
553
570
|
if (column.typeRef !== undefined) continue;
|
|
554
|
-
const ref = codecDescriptors.codecRefForColumn(tableName, columnName);
|
|
571
|
+
const ref = codecDescriptors.codecRefForColumn(namespaceId, tableName, columnName);
|
|
555
572
|
if (!ref) continue;
|
|
556
573
|
const key = refKeyOf(ref);
|
|
557
574
|
const site = { table: tableName, column: columnName };
|
|
@@ -579,10 +596,10 @@ function buildContractCodecRegistry(
|
|
|
579
596
|
};
|
|
580
597
|
});
|
|
581
598
|
|
|
582
|
-
for (const ns of Object.
|
|
583
|
-
for (const [tableName, table] of Object.entries(ns.
|
|
599
|
+
for (const [namespaceId, ns] of Object.entries(contract.storage.namespaces)) {
|
|
600
|
+
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
584
601
|
for (const columnName of Object.keys(table.columns)) {
|
|
585
|
-
const ref = codecDescriptors.codecRefForColumn(tableName, columnName);
|
|
602
|
+
const ref = codecDescriptors.codecRefForColumn(namespaceId, tableName, columnName);
|
|
586
603
|
if (!ref) continue;
|
|
587
604
|
resolver.forCodecRef(ref);
|
|
588
605
|
}
|
|
@@ -590,8 +607,8 @@ function buildContractCodecRegistry(
|
|
|
590
607
|
}
|
|
591
608
|
|
|
592
609
|
const registry: ContractCodecRegistry = {
|
|
593
|
-
forColumn(table, column) {
|
|
594
|
-
const ref = codecDescriptors.codecRefForColumn(table, column);
|
|
610
|
+
forColumn(namespaceId, table, column) {
|
|
611
|
+
const ref = codecDescriptors.codecRefForColumn(namespaceId, table, column);
|
|
595
612
|
return ref ? resolver.forCodecRef(ref) : undefined;
|
|
596
613
|
},
|
|
597
614
|
forCodecRef(ref) {
|
package/src/sql-runtime.ts
CHANGED
|
@@ -761,6 +761,21 @@ export async function withTransaction<R>(
|
|
|
761
761
|
const transaction = await connection.transaction();
|
|
762
762
|
|
|
763
763
|
let invalidated = false;
|
|
764
|
+
|
|
765
|
+
async function* guardedStream<Row>(
|
|
766
|
+
inner: AsyncIterable<Row>,
|
|
767
|
+
): AsyncGenerator<Row, void, unknown> {
|
|
768
|
+
if (invalidated) {
|
|
769
|
+
throw transactionClosedError();
|
|
770
|
+
}
|
|
771
|
+
for await (const row of inner) {
|
|
772
|
+
yield row;
|
|
773
|
+
if (invalidated) {
|
|
774
|
+
throw transactionClosedError();
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
764
779
|
const txContext: TransactionContext = {
|
|
765
780
|
get invalidated() {
|
|
766
781
|
return invalidated;
|
|
@@ -772,16 +787,7 @@ export async function withTransaction<R>(
|
|
|
772
787
|
if (invalidated) {
|
|
773
788
|
throw transactionClosedError();
|
|
774
789
|
}
|
|
775
|
-
|
|
776
|
-
const guarded = async function* (): AsyncGenerator<Row, void, unknown> {
|
|
777
|
-
for await (const row of inner) {
|
|
778
|
-
if (invalidated) {
|
|
779
|
-
throw transactionClosedError();
|
|
780
|
-
}
|
|
781
|
-
yield row;
|
|
782
|
-
}
|
|
783
|
-
};
|
|
784
|
-
return new AsyncIterableResult(guarded());
|
|
790
|
+
return new AsyncIterableResult(guardedStream(transaction.execute(plan, options)));
|
|
785
791
|
},
|
|
786
792
|
executePrepared<Params, Row>(
|
|
787
793
|
ps: PreparedStatement<Params, Row>,
|
|
@@ -791,16 +797,9 @@ export async function withTransaction<R>(
|
|
|
791
797
|
if (invalidated) {
|
|
792
798
|
throw transactionClosedError();
|
|
793
799
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
if (invalidated) {
|
|
798
|
-
throw transactionClosedError();
|
|
799
|
-
}
|
|
800
|
-
yield row;
|
|
801
|
-
}
|
|
802
|
-
};
|
|
803
|
-
return new AsyncIterableResult(guarded());
|
|
800
|
+
return new AsyncIterableResult(
|
|
801
|
+
guardedStream(transaction.executePrepared(ps, params, options)),
|
|
802
|
+
);
|
|
804
803
|
},
|
|
805
804
|
};
|
|
806
805
|
|