@prisma-next/sql-contract-ts 0.13.0 → 0.14.0
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 +12 -9
- package/dist/{build-contract-C-x2pfu4.mjs → build-contract-CQ4u83jx.mjs} +24 -54
- package/dist/build-contract-CQ4u83jx.mjs.map +1 -0
- package/dist/config-types.mjs +1 -1
- package/dist/contract-builder.d.mts +129 -63
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +48 -11
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +10 -10
- package/src/build-contract.ts +33 -91
- package/src/contract-builder.ts +47 -31
- package/src/contract-definition.ts +11 -23
- package/src/contract-dsl.ts +41 -17
- package/src/contract-lowering.ts +19 -26
- package/src/contract-types.ts +135 -32
- package/src/contract-warnings.ts +3 -6
- package/src/enum-type.ts +98 -28
- package/src/exports/contract-builder.ts +10 -2
- package/dist/build-contract-C-x2pfu4.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-contract-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "SQL-specific TypeScript contract authoring surface for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/config": "0.
|
|
10
|
-
"@prisma-next/contract": "0.
|
|
11
|
-
"@prisma-next/contract-authoring": "0.
|
|
12
|
-
"@prisma-next/framework-components": "0.
|
|
13
|
-
"@prisma-next/sql-contract": "0.
|
|
14
|
-
"@prisma-next/utils": "0.
|
|
9
|
+
"@prisma-next/config": "0.14.0",
|
|
10
|
+
"@prisma-next/contract": "0.14.0",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.14.0",
|
|
12
|
+
"@prisma-next/framework-components": "0.14.0",
|
|
13
|
+
"@prisma-next/sql-contract": "0.14.0",
|
|
14
|
+
"@prisma-next/utils": "0.14.0",
|
|
15
15
|
"arktype": "^2.2.0",
|
|
16
16
|
"pathe": "^2.0.3",
|
|
17
17
|
"ts-toolbelt": "^9.6.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@prisma-next/test-utils": "0.
|
|
21
|
-
"@prisma-next/tsconfig": "0.
|
|
20
|
+
"@prisma-next/test-utils": "0.14.0",
|
|
21
|
+
"@prisma-next/tsconfig": "0.14.0",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.21.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.
|
|
24
|
+
"@prisma-next/tsdown": "0.14.0",
|
|
25
25
|
"tsdown": "0.22.1",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.8"
|
package/src/build-contract.ts
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
asNamespaceId,
|
|
8
8
|
type ColumnDefault,
|
|
9
|
-
type ColumnDefaultLiteralInputValue,
|
|
10
9
|
type Contract,
|
|
11
10
|
type ContractEnum,
|
|
12
11
|
type ContractField,
|
|
@@ -36,13 +35,10 @@ import {
|
|
|
36
35
|
applyFkDefaults,
|
|
37
36
|
buildSqlNamespace,
|
|
38
37
|
type CheckConstraintInput,
|
|
39
|
-
isPostgresEnumStorageEntry,
|
|
40
|
-
type PostgresEnumStorageEntry,
|
|
41
38
|
type SqlNamespaceTablesInput,
|
|
42
39
|
SqlStorage,
|
|
43
40
|
type SqlStorageInput,
|
|
44
41
|
type StorageColumn,
|
|
45
|
-
StorageTable,
|
|
46
42
|
type StorageTableInput,
|
|
47
43
|
type StorageTypeInstance,
|
|
48
44
|
type StorageValueSetInput,
|
|
@@ -63,16 +59,15 @@ type DomainFieldRef =
|
|
|
63
59
|
| { readonly kind: 'scalar'; readonly many?: boolean }
|
|
64
60
|
| { readonly kind: 'valueObject'; readonly name: string; readonly many?: boolean };
|
|
65
61
|
|
|
66
|
-
function
|
|
67
|
-
value: ColumnDefaultLiteralInputValue,
|
|
68
|
-
codecId: string,
|
|
69
|
-
codecLookup?: CodecLookup,
|
|
70
|
-
): JsonValue {
|
|
62
|
+
function encodeViaCodec(value: unknown, codecId: string, codecLookup?: CodecLookup): JsonValue {
|
|
71
63
|
const codec = codecLookup?.get(codecId);
|
|
72
64
|
if (codec) {
|
|
73
65
|
return codec.encodeJson(value);
|
|
74
66
|
}
|
|
75
|
-
return
|
|
67
|
+
return blindCast<
|
|
68
|
+
JsonValue,
|
|
69
|
+
'no codec lookup at build time: literal/enum member value is already JSON-safe'
|
|
70
|
+
>(value);
|
|
76
71
|
}
|
|
77
72
|
|
|
78
73
|
function encodeColumnDefault(
|
|
@@ -85,7 +80,7 @@ function encodeColumnDefault(
|
|
|
85
80
|
}
|
|
86
81
|
return {
|
|
87
82
|
kind: 'literal',
|
|
88
|
-
value:
|
|
83
|
+
value: encodeViaCodec(defaultInput.value, codecId, codecLookup),
|
|
89
84
|
};
|
|
90
85
|
}
|
|
91
86
|
|
|
@@ -185,13 +180,18 @@ function buildThroughDescriptor(
|
|
|
185
180
|
targetModel: ModelNode,
|
|
186
181
|
modelName: string,
|
|
187
182
|
fieldName: string,
|
|
183
|
+
defaultNamespaceId: string,
|
|
188
184
|
): ContractRelationThrough {
|
|
189
|
-
|
|
190
|
-
if (namespaceId === undefined) {
|
|
185
|
+
if (!tableNamespaceByName.has(through.table)) {
|
|
191
186
|
throw new Error(
|
|
192
187
|
`buildSqlContractFromDefinition: junction table "${through.table}" for relation "${modelName}.${fieldName}" is not a declared model.`,
|
|
193
188
|
);
|
|
194
189
|
}
|
|
190
|
+
// Junction table names are unique per namespace, not globally. Prefer the
|
|
191
|
+
// junction's own declared namespace (carried on the through node); fall back to
|
|
192
|
+
// the target's default namespace. Resolving by bare table name would pick the
|
|
193
|
+
// wrong namespace when the same junction table name exists in two namespaces.
|
|
194
|
+
const namespaceId = through.namespaceId ?? defaultNamespaceId;
|
|
195
195
|
|
|
196
196
|
return {
|
|
197
197
|
table: through.table,
|
|
@@ -322,55 +322,6 @@ function ensureUnboundNamespaceSlot(
|
|
|
322
322
|
});
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
const POSTGRES_ENUM_NAMESPACE_ID = 'public';
|
|
326
|
-
|
|
327
|
-
function partitionStorageTypesForTarget(
|
|
328
|
-
targetId: string,
|
|
329
|
-
types: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
330
|
-
namespaceTypes?: Readonly<Record<string, Readonly<Record<string, PostgresEnumStorageEntry>>>>,
|
|
331
|
-
): {
|
|
332
|
-
readonly documentTypes: Record<string, StorageTypeInstance>;
|
|
333
|
-
readonly namespaceEnumTypesById: Record<string, Record<string, PostgresEnumStorageEntry>>;
|
|
334
|
-
} {
|
|
335
|
-
const documentTypes: Record<string, StorageTypeInstance> = {};
|
|
336
|
-
const namespaceEnumTypesById: Record<string, Record<string, PostgresEnumStorageEntry>> = {};
|
|
337
|
-
for (const [name, entry] of Object.entries(types)) {
|
|
338
|
-
if (isPostgresEnumStorageEntry(entry)) {
|
|
339
|
-
if (targetId !== 'postgres') {
|
|
340
|
-
throw new Error(
|
|
341
|
-
`buildSqlContractFromDefinition: postgres enum "${name}" is only valid when target is "postgres" (got "${targetId}").`,
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
let slot = namespaceEnumTypesById[POSTGRES_ENUM_NAMESPACE_ID];
|
|
345
|
-
if (slot === undefined) {
|
|
346
|
-
slot = {};
|
|
347
|
-
namespaceEnumTypesById[POSTGRES_ENUM_NAMESPACE_ID] = slot;
|
|
348
|
-
}
|
|
349
|
-
slot[name] = entry;
|
|
350
|
-
continue;
|
|
351
|
-
}
|
|
352
|
-
documentTypes[name] = entry;
|
|
353
|
-
}
|
|
354
|
-
if (namespaceTypes !== undefined) {
|
|
355
|
-
for (const [nsId, enumsInNs] of Object.entries(namespaceTypes)) {
|
|
356
|
-
for (const [name, entry] of Object.entries(enumsInNs)) {
|
|
357
|
-
if (targetId !== 'postgres') {
|
|
358
|
-
throw new Error(
|
|
359
|
-
`buildSqlContractFromDefinition: postgres enum "${name}" is only valid when target is "postgres" (got "${targetId}").`,
|
|
360
|
-
);
|
|
361
|
-
}
|
|
362
|
-
let slot = namespaceEnumTypesById[nsId];
|
|
363
|
-
if (slot === undefined) {
|
|
364
|
-
slot = {};
|
|
365
|
-
namespaceEnumTypesById[nsId] = slot;
|
|
366
|
-
}
|
|
367
|
-
slot[name] = entry;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
return { documentTypes, namespaceEnumTypesById };
|
|
372
|
-
}
|
|
373
|
-
|
|
374
325
|
export function buildSqlContractFromDefinition(
|
|
375
326
|
definition: ContractDefinition,
|
|
376
327
|
codecLookup?: CodecLookup,
|
|
@@ -391,7 +342,7 @@ export function buildSqlContractFromDefinition(
|
|
|
391
342
|
definition.models.map((m) => [`${resolveNamespaceId(m)}:${m.modelName}`, m]),
|
|
392
343
|
);
|
|
393
344
|
|
|
394
|
-
const tablesByNamespace: Record<string, Record<string,
|
|
345
|
+
const tablesByNamespace: Record<string, Record<string, StorageTableInput>> = {};
|
|
395
346
|
const modelNameToNamespaceId = new Map<string, string>();
|
|
396
347
|
const executionDefaults: ExecutionMutationDefault[] = [];
|
|
397
348
|
const modelsByNamespace: Record<string, Record<string, ContractModel>> = {};
|
|
@@ -451,9 +402,9 @@ export function buildSqlContractFromDefinition(
|
|
|
451
402
|
enumHandle !== undefined
|
|
452
403
|
? {
|
|
453
404
|
plane: 'storage',
|
|
454
|
-
entityKind: '
|
|
405
|
+
entityKind: 'valueSet',
|
|
455
406
|
namespaceId: defaultNamespaceId,
|
|
456
|
-
|
|
407
|
+
entityName: enumHandle.enumName,
|
|
457
408
|
}
|
|
458
409
|
: undefined;
|
|
459
410
|
const domainValueSetRef: ValueSetRef | undefined =
|
|
@@ -462,7 +413,7 @@ export function buildSqlContractFromDefinition(
|
|
|
462
413
|
plane: 'domain',
|
|
463
414
|
entityKind: 'enum',
|
|
464
415
|
namespaceId: defaultNamespaceId,
|
|
465
|
-
|
|
416
|
+
entityName: enumHandle.enumName,
|
|
466
417
|
}
|
|
467
418
|
: undefined;
|
|
468
419
|
|
|
@@ -484,7 +435,7 @@ export function buildSqlContractFromDefinition(
|
|
|
484
435
|
|
|
485
436
|
if (executionDefaultPhases) {
|
|
486
437
|
executionDefaults.push({
|
|
487
|
-
ref: { table: tableName, column: field.columnName },
|
|
438
|
+
ref: { namespace: namespaceId, table: tableName, column: field.columnName },
|
|
488
439
|
...ifDefined('onCreate', executionDefaultPhases.onCreate),
|
|
489
440
|
...ifDefined('onUpdate', executionDefaultPhases.onUpdate),
|
|
490
441
|
});
|
|
@@ -604,7 +555,7 @@ export function buildSqlContractFromDefinition(
|
|
|
604
555
|
`buildSqlContractFromDefinition: duplicate table "${tableName}" in namespace "${namespaceId}".`,
|
|
605
556
|
);
|
|
606
557
|
}
|
|
607
|
-
nsTables[tableName] =
|
|
558
|
+
nsTables[tableName] = tableInput;
|
|
608
559
|
}
|
|
609
560
|
|
|
610
561
|
// --- Build contract model ---
|
|
@@ -678,6 +629,7 @@ export function buildSqlContractFromDefinition(
|
|
|
678
629
|
targetModel,
|
|
679
630
|
semanticModel.modelName,
|
|
680
631
|
relation.fieldName,
|
|
632
|
+
defaultNamespaceId,
|
|
681
633
|
),
|
|
682
634
|
};
|
|
683
635
|
} else {
|
|
@@ -725,13 +677,9 @@ export function buildSqlContractFromDefinition(
|
|
|
725
677
|
// discriminator shape before hashing so the storageHash matches the
|
|
726
678
|
// persisted JSON envelope produced from the SqlStorage class instance
|
|
727
679
|
// (which always carries the discriminator).
|
|
728
|
-
const rawStorageTypes =
|
|
729
|
-
|
|
730
|
-
StorageTypeInstance | PostgresEnumStorageEntry
|
|
731
|
-
>;
|
|
732
|
-
const storageTypes = Object.fromEntries(
|
|
680
|
+
const rawStorageTypes = definition.storageTypes ?? {};
|
|
681
|
+
const documentTypes: Record<string, StorageTypeInstance> = Object.fromEntries(
|
|
733
682
|
Object.entries(rawStorageTypes).map(([name, entry]) => {
|
|
734
|
-
if (isPostgresEnumStorageEntry(entry)) return [name, entry];
|
|
735
683
|
if ((entry as { kind?: unknown }).kind === 'codec-instance') return [name, entry];
|
|
736
684
|
return [
|
|
737
685
|
name,
|
|
@@ -743,15 +691,7 @@ export function buildSqlContractFromDefinition(
|
|
|
743
691
|
];
|
|
744
692
|
}),
|
|
745
693
|
);
|
|
746
|
-
const { documentTypes, namespaceEnumTypesById } = partitionStorageTypesForTarget(
|
|
747
|
-
target,
|
|
748
|
-
storageTypes,
|
|
749
|
-
definition.namespaceTypes,
|
|
750
|
-
);
|
|
751
694
|
const namespaceCoordinateIds = collectStorageNamespaceCoordinateIds(definition);
|
|
752
|
-
for (const id of Object.keys(namespaceEnumTypesById)) {
|
|
753
|
-
namespaceCoordinateIds.add(id);
|
|
754
|
-
}
|
|
755
695
|
|
|
756
696
|
// Build per-namespace registries for `enumType()` handles.
|
|
757
697
|
// All authored enums target the contract's default namespace.
|
|
@@ -771,7 +711,10 @@ export function buildSqlContractFromDefinition(
|
|
|
771
711
|
}
|
|
772
712
|
domainSlot[enumName] = {
|
|
773
713
|
codecId: handle.codecId,
|
|
774
|
-
members: handle.enumMembers
|
|
714
|
+
members: handle.enumMembers.map((m) => ({
|
|
715
|
+
name: m.name,
|
|
716
|
+
value: encodeViaCodec(m.value, handle.codecId, codecLookup),
|
|
717
|
+
})),
|
|
775
718
|
};
|
|
776
719
|
|
|
777
720
|
let storageSlot = storageValueSetsByNs[nsId];
|
|
@@ -780,8 +723,8 @@ export function buildSqlContractFromDefinition(
|
|
|
780
723
|
storageValueSetsByNs[nsId] = storageSlot;
|
|
781
724
|
}
|
|
782
725
|
storageSlot[enumName] = {
|
|
783
|
-
kind: '
|
|
784
|
-
values: handle.values,
|
|
726
|
+
kind: 'valueSet',
|
|
727
|
+
values: handle.values.map((v) => encodeViaCodec(v, handle.codecId, codecLookup)),
|
|
785
728
|
};
|
|
786
729
|
}
|
|
787
730
|
|
|
@@ -792,7 +735,6 @@ export function buildSqlContractFromDefinition(
|
|
|
792
735
|
>(
|
|
793
736
|
Object.fromEntries(
|
|
794
737
|
[...namespaceCoordinateIds].sort().map((id) => {
|
|
795
|
-
const enumTypes = namespaceEnumTypesById[id];
|
|
796
738
|
const valueSetEntries = storageValueSetsByNs[id];
|
|
797
739
|
const nsInput: SqlNamespaceTablesInput = {
|
|
798
740
|
id,
|
|
@@ -803,16 +745,16 @@ export function buildSqlContractFromDefinition(
|
|
|
803
745
|
: {}),
|
|
804
746
|
},
|
|
805
747
|
};
|
|
806
|
-
return [
|
|
807
|
-
id,
|
|
808
|
-
createNamespace ? createNamespace(nsInput, enumTypes) : buildSqlNamespace(nsInput),
|
|
809
|
-
];
|
|
748
|
+
return [id, createNamespace ? createNamespace(nsInput) : buildSqlNamespace(nsInput)];
|
|
810
749
|
}),
|
|
811
750
|
),
|
|
812
751
|
);
|
|
813
752
|
const storageWithoutHash = {
|
|
814
753
|
...(Object.keys(documentTypes).length > 0 ? { types: documentTypes } : {}),
|
|
815
|
-
namespaces:
|
|
754
|
+
namespaces:
|
|
755
|
+
defaultNamespaceId === UNBOUND_NAMESPACE_ID
|
|
756
|
+
? ensureUnboundNamespaceSlot(namespaces, createNamespace)
|
|
757
|
+
: namespaces,
|
|
816
758
|
};
|
|
817
759
|
const storageHash: StorageHashBase<string> = definition.storageHash
|
|
818
760
|
? coreHash(definition.storageHash)
|
package/src/contract-builder.ts
CHANGED
|
@@ -7,11 +7,7 @@ import type {
|
|
|
7
7
|
TargetPackRef,
|
|
8
8
|
} from '@prisma-next/framework-components/components';
|
|
9
9
|
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
10
|
-
import type {
|
|
11
|
-
PostgresEnumStorageEntry,
|
|
12
|
-
SqlNamespaceTablesInput,
|
|
13
|
-
StorageTypeInstance,
|
|
14
|
-
} from '@prisma-next/sql-contract/types';
|
|
10
|
+
import type { SqlNamespaceTablesInput, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
15
11
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
16
12
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
17
13
|
import { buildSqlContractFromDefinition } from './build-contract';
|
|
@@ -55,13 +51,14 @@ type ModelLike = {
|
|
|
55
51
|
type ContractDefinition<
|
|
56
52
|
Family extends FamilyPackRef<string>,
|
|
57
53
|
Target extends TargetPackRef<'sql', string>,
|
|
58
|
-
Types extends Record<string, StorageTypeInstance
|
|
54
|
+
Types extends Record<string, StorageTypeInstance>,
|
|
59
55
|
Models extends Record<string, ModelLike>,
|
|
60
56
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
61
57
|
Naming extends ContractInput['naming'] | undefined,
|
|
62
58
|
StorageHash extends string | undefined,
|
|
63
59
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
64
60
|
Namespaces extends readonly string[] | undefined = undefined,
|
|
61
|
+
Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
65
62
|
> = {
|
|
66
63
|
readonly family: Family;
|
|
67
64
|
readonly target: Target;
|
|
@@ -75,7 +72,7 @@ type ContractDefinition<
|
|
|
75
72
|
readonly types?: Types;
|
|
76
73
|
readonly models?: Models;
|
|
77
74
|
readonly codecLookup?: CodecLookup;
|
|
78
|
-
readonly enums?:
|
|
75
|
+
readonly enums?: Enums;
|
|
79
76
|
};
|
|
80
77
|
|
|
81
78
|
type ContractScaffold<
|
|
@@ -86,6 +83,7 @@ type ContractScaffold<
|
|
|
86
83
|
StorageHash extends string | undefined,
|
|
87
84
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
88
85
|
Namespaces extends readonly string[] | undefined = undefined,
|
|
86
|
+
Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
89
87
|
> = {
|
|
90
88
|
readonly family: Family;
|
|
91
89
|
readonly target: Target;
|
|
@@ -99,18 +97,20 @@ type ContractScaffold<
|
|
|
99
97
|
readonly types?: never;
|
|
100
98
|
readonly models?: never;
|
|
101
99
|
readonly codecLookup?: CodecLookup;
|
|
102
|
-
readonly enums?:
|
|
100
|
+
readonly enums?: Enums;
|
|
103
101
|
};
|
|
104
102
|
|
|
105
103
|
type ContractFactory<
|
|
106
104
|
Family extends FamilyPackRef<string>,
|
|
107
105
|
Target extends TargetPackRef<'sql', string>,
|
|
108
|
-
Types extends Record<string, StorageTypeInstance
|
|
106
|
+
Types extends Record<string, StorageTypeInstance>,
|
|
109
107
|
Models extends Record<string, ModelLike>,
|
|
110
108
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
109
|
+
Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
111
110
|
> = (helpers: ComposedAuthoringHelpers<Family, Target, ExtensionPacks>) => {
|
|
112
111
|
readonly types?: Types;
|
|
113
112
|
readonly models?: Models;
|
|
113
|
+
readonly enums?: Enums;
|
|
114
114
|
};
|
|
115
115
|
|
|
116
116
|
function validateTargetPackRef(
|
|
@@ -300,10 +300,7 @@ function buildContractFromDsl<Definition extends ContractInput>(
|
|
|
300
300
|
// Input for buildBoundContract — all fields from ContractInput except family/target
|
|
301
301
|
// (those are injected by the builder, pre-bound at the call site).
|
|
302
302
|
type BoundDefinitionInput<
|
|
303
|
-
Types extends Record<string, StorageTypeInstance
|
|
304
|
-
never,
|
|
305
|
-
never
|
|
306
|
-
>,
|
|
303
|
+
Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
307
304
|
Models extends Record<string, ModelLike> = Record<never, never>,
|
|
308
305
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined = undefined,
|
|
309
306
|
Naming extends ContractInput['naming'] | undefined = undefined,
|
|
@@ -324,6 +321,20 @@ type BoundDefinitionInput<
|
|
|
324
321
|
readonly enums?: Record<string, EnumTypeHandle>;
|
|
325
322
|
};
|
|
326
323
|
|
|
324
|
+
// A bare `Record<string, EnumTypeHandle>` (no literal keys) is the widened
|
|
325
|
+
// default for a side that declared no enums; drop it so the merge keeps only
|
|
326
|
+
// literally-authored enum handles.
|
|
327
|
+
type LiteralEnums<E extends Record<string, EnumTypeHandle>> = string extends keyof E
|
|
328
|
+
? Record<never, never>
|
|
329
|
+
: E;
|
|
330
|
+
|
|
331
|
+
// Merges enum handles authored on the scaffold definition with those returned
|
|
332
|
+
// from the factory callback. Either side may be the widened default (empty).
|
|
333
|
+
export type MergeEnums<
|
|
334
|
+
ScaffoldEnums extends Record<string, EnumTypeHandle>,
|
|
335
|
+
FactoryEnums extends Record<string, EnumTypeHandle>,
|
|
336
|
+
> = LiteralEnums<ScaffoldEnums> & LiteralEnums<FactoryEnums>;
|
|
337
|
+
|
|
327
338
|
// Merges a bound input with the pre-bound family/target to produce a full ContractDefinition.
|
|
328
339
|
type WithFamilyTarget<
|
|
329
340
|
Input,
|
|
@@ -343,7 +354,7 @@ export function buildBoundContract<
|
|
|
343
354
|
const F extends FamilyPackRef<string>,
|
|
344
355
|
const T extends TargetPackRef<'sql', string>,
|
|
345
356
|
const Definition extends BoundDefinitionInput<
|
|
346
|
-
Record<string, StorageTypeInstance
|
|
357
|
+
Record<string, StorageTypeInstance>,
|
|
347
358
|
Record<string, ModelLike>,
|
|
348
359
|
Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
349
360
|
ContractInput['naming'] | undefined,
|
|
@@ -364,7 +375,7 @@ export function buildBoundContract<
|
|
|
364
375
|
const F extends FamilyPackRef<string>,
|
|
365
376
|
const T extends TargetPackRef<'sql', string>,
|
|
366
377
|
const Definition extends BoundDefinitionInput<
|
|
367
|
-
Record<string, StorageTypeInstance
|
|
378
|
+
Record<string, StorageTypeInstance>,
|
|
368
379
|
Record<string, ModelLike>,
|
|
369
380
|
Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
370
381
|
ContractInput['naming'] | undefined,
|
|
@@ -373,8 +384,9 @@ export function buildBoundContract<
|
|
|
373
384
|
readonly string[] | undefined
|
|
374
385
|
>,
|
|
375
386
|
const Built extends {
|
|
376
|
-
readonly types?: Record<string, StorageTypeInstance
|
|
387
|
+
readonly types?: Record<string, StorageTypeInstance>;
|
|
377
388
|
readonly models?: Record<string, ModelLike>;
|
|
389
|
+
readonly enums?: Record<string, EnumTypeHandle>;
|
|
378
390
|
},
|
|
379
391
|
>(
|
|
380
392
|
family: F,
|
|
@@ -397,8 +409,9 @@ export function buildBoundContract(
|
|
|
397
409
|
Record<string, ExtensionPackRef<'sql', string>> | undefined
|
|
398
410
|
>,
|
|
399
411
|
) => {
|
|
400
|
-
readonly types?: Record<string, StorageTypeInstance
|
|
412
|
+
readonly types?: Record<string, StorageTypeInstance>;
|
|
401
413
|
readonly models?: Record<string, ModelLike>;
|
|
414
|
+
readonly enums?: Record<string, EnumTypeHandle>;
|
|
402
415
|
})
|
|
403
416
|
| undefined,
|
|
404
417
|
) {
|
|
@@ -412,10 +425,12 @@ export function buildBoundContract(
|
|
|
412
425
|
extensionPacks: definition.extensionPacks,
|
|
413
426
|
}),
|
|
414
427
|
);
|
|
428
|
+
const mergedEnums = { ...(definition.enums ?? {}), ...built.enums };
|
|
415
429
|
return buildContractFromDsl({
|
|
416
430
|
...full,
|
|
417
431
|
...ifDefined('types', built.types),
|
|
418
432
|
...ifDefined('models', built.models),
|
|
433
|
+
...ifDefined('enums', Object.keys(mergedEnums).length > 0 ? mergedEnums : undefined),
|
|
419
434
|
});
|
|
420
435
|
}
|
|
421
436
|
|
|
@@ -425,10 +440,7 @@ export function buildBoundContract(
|
|
|
425
440
|
export function defineContract<
|
|
426
441
|
const Family extends FamilyPackRef<string>,
|
|
427
442
|
const Target extends TargetPackRef<'sql', string>,
|
|
428
|
-
const Types extends Record<string, StorageTypeInstance
|
|
429
|
-
never,
|
|
430
|
-
never
|
|
431
|
-
>,
|
|
443
|
+
const Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
432
444
|
const Models extends Record<string, ModelLike> = Record<never, never>,
|
|
433
445
|
const ExtensionPacks extends
|
|
434
446
|
| Record<string, ExtensionPackRef<'sql', string>>
|
|
@@ -437,6 +449,7 @@ export function defineContract<
|
|
|
437
449
|
const StorageHash extends string | undefined = undefined,
|
|
438
450
|
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
439
451
|
const Namespaces extends readonly string[] | undefined = undefined,
|
|
452
|
+
const Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
440
453
|
>(
|
|
441
454
|
definition: ContractDefinition<
|
|
442
455
|
Family,
|
|
@@ -447,7 +460,8 @@ export function defineContract<
|
|
|
447
460
|
Naming,
|
|
448
461
|
StorageHash,
|
|
449
462
|
ForeignKeyDefaults,
|
|
450
|
-
Namespaces
|
|
463
|
+
Namespaces,
|
|
464
|
+
Enums
|
|
451
465
|
>,
|
|
452
466
|
): SqlContractResult<
|
|
453
467
|
ContractDefinition<
|
|
@@ -459,16 +473,14 @@ export function defineContract<
|
|
|
459
473
|
Naming,
|
|
460
474
|
StorageHash,
|
|
461
475
|
ForeignKeyDefaults,
|
|
462
|
-
Namespaces
|
|
476
|
+
Namespaces,
|
|
477
|
+
Enums
|
|
463
478
|
>
|
|
464
479
|
>;
|
|
465
480
|
export function defineContract<
|
|
466
481
|
const Family extends FamilyPackRef<string>,
|
|
467
482
|
const Target extends TargetPackRef<'sql', string>,
|
|
468
|
-
const Types extends Record<string, StorageTypeInstance
|
|
469
|
-
never,
|
|
470
|
-
never
|
|
471
|
-
>,
|
|
483
|
+
const Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
472
484
|
const Models extends Record<string, ModelLike> = Record<never, never>,
|
|
473
485
|
const ExtensionPacks extends
|
|
474
486
|
| Record<string, ExtensionPackRef<'sql', string>>
|
|
@@ -477,6 +489,8 @@ export function defineContract<
|
|
|
477
489
|
const StorageHash extends string | undefined = undefined,
|
|
478
490
|
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
479
491
|
const Namespaces extends readonly string[] | undefined = undefined,
|
|
492
|
+
const ScaffoldEnums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
493
|
+
const FactoryEnums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
480
494
|
>(
|
|
481
495
|
definition: ContractScaffold<
|
|
482
496
|
Family,
|
|
@@ -485,9 +499,10 @@ export function defineContract<
|
|
|
485
499
|
Naming,
|
|
486
500
|
StorageHash,
|
|
487
501
|
ForeignKeyDefaults,
|
|
488
|
-
Namespaces
|
|
502
|
+
Namespaces,
|
|
503
|
+
ScaffoldEnums
|
|
489
504
|
>,
|
|
490
|
-
factory: ContractFactory<Family, Target, Types, Models, ExtensionPacks>,
|
|
505
|
+
factory: ContractFactory<Family, Target, Types, Models, ExtensionPacks, FactoryEnums>,
|
|
491
506
|
): SqlContractResult<
|
|
492
507
|
ContractDefinition<
|
|
493
508
|
Family,
|
|
@@ -498,7 +513,8 @@ export function defineContract<
|
|
|
498
513
|
Naming,
|
|
499
514
|
StorageHash,
|
|
500
515
|
ForeignKeyDefaults,
|
|
501
|
-
Namespaces
|
|
516
|
+
Namespaces,
|
|
517
|
+
MergeEnums<ScaffoldEnums, FactoryEnums>
|
|
502
518
|
>
|
|
503
519
|
>;
|
|
504
520
|
export function defineContract(
|
|
@@ -506,7 +522,7 @@ export function defineContract(
|
|
|
506
522
|
factory?: ContractFactory<
|
|
507
523
|
FamilyPackRef<string>,
|
|
508
524
|
TargetPackRef<'sql', string>,
|
|
509
|
-
Record<string, StorageTypeInstance
|
|
525
|
+
Record<string, StorageTypeInstance>,
|
|
510
526
|
Record<string, ModelLike>,
|
|
511
527
|
Record<string, ExtensionPackRef<'sql', string>> | undefined
|
|
512
528
|
>,
|
|
@@ -8,7 +8,6 @@ import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/cod
|
|
|
8
8
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
9
9
|
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
10
10
|
import type {
|
|
11
|
-
PostgresEnumStorageEntry,
|
|
12
11
|
ReferentialAction,
|
|
13
12
|
SqlNamespaceTablesInput,
|
|
14
13
|
StorageTypeInstance,
|
|
@@ -105,6 +104,14 @@ export interface RelationNode {
|
|
|
105
104
|
};
|
|
106
105
|
readonly through?: {
|
|
107
106
|
readonly table: string;
|
|
107
|
+
/**
|
|
108
|
+
* Namespace the junction table lives in. Set from the junction model's
|
|
109
|
+
* declared namespace at lowering time; junction table names are unique per
|
|
110
|
+
* namespace, not globally, so this disambiguates a junction whose bare table
|
|
111
|
+
* name also exists in another namespace. Omitted for a junction in the
|
|
112
|
+
* default namespace (resolved to the target's default at build time).
|
|
113
|
+
*/
|
|
114
|
+
readonly namespaceId?: string;
|
|
108
115
|
readonly parentColumns: readonly string[];
|
|
109
116
|
readonly childColumns: readonly string[];
|
|
110
117
|
};
|
|
@@ -162,33 +169,14 @@ export interface ContractDefinition {
|
|
|
162
169
|
readonly extensionPacks?: Record<string, ExtensionPackRef<'sql', string>>;
|
|
163
170
|
readonly storageHash?: string;
|
|
164
171
|
readonly foreignKeyDefaults?: ForeignKeyDefaultsState;
|
|
165
|
-
readonly storageTypes?: Record<string, StorageTypeInstance
|
|
166
|
-
/**
|
|
167
|
-
* Enum types declared inside a named `namespace { enum … }` block,
|
|
168
|
-
* keyed first by namespace id then by type name. These are routed to
|
|
169
|
-
* `storage.namespaces[nsId].entries.type` rather than the implicit fallback
|
|
170
|
-
* namespace used for top-level `storageTypes` enums.
|
|
171
|
-
*/
|
|
172
|
-
readonly namespaceTypes?: Readonly<
|
|
173
|
-
Record<string, Readonly<Record<string, PostgresEnumStorageEntry>>>
|
|
174
|
-
>;
|
|
172
|
+
readonly storageTypes?: Record<string, StorageTypeInstance>;
|
|
175
173
|
/**
|
|
176
174
|
* Declared namespace coordinates for this contract — populates
|
|
177
175
|
* `SqlStorage.namespaces` together with `createNamespace`.
|
|
178
176
|
*/
|
|
179
177
|
readonly namespaces?: readonly string[];
|
|
180
|
-
/**
|
|
181
|
-
|
|
182
|
-
* for a declared namespace coordinate. Mirrors
|
|
183
|
-
* `ContractInput.createNamespace`.
|
|
184
|
-
*
|
|
185
|
-
* The optional second argument carries target-specific enum types for the
|
|
186
|
-
* namespace (e.g. postgres enum registrations keyed by type name).
|
|
187
|
-
*/
|
|
188
|
-
readonly createNamespace?: (
|
|
189
|
-
input: SqlNamespaceTablesInput,
|
|
190
|
-
enumTypes?: Readonly<Record<string, PostgresEnumStorageEntry>>,
|
|
191
|
-
) => Namespace;
|
|
178
|
+
/** Target-supplied factory that materialises a `Namespace` concretion for a declared namespace coordinate. */
|
|
179
|
+
readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
|
|
192
180
|
readonly models: readonly ModelNode[];
|
|
193
181
|
readonly valueObjects?: readonly ValueObjectNode[];
|
|
194
182
|
/**
|