@prisma-next/sql-contract-ts 0.13.0-dev.3 → 0.13.0-dev.30
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-Bu6zubET.mjs} +18 -49
- package/dist/build-contract-Bu6zubET.mjs.map +1 -0
- package/dist/config-types.mjs +1 -1
- package/dist/contract-builder.d.mts +111 -60
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +43 -9
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +10 -10
- package/src/build-contract.ts +20 -87
- package/src/contract-builder.ts +47 -31
- package/src/contract-definition.ts +3 -23
- package/src/contract-dsl.ts +41 -17
- package/src/contract-lowering.ts +12 -24
- package/src/contract-types.ts +105 -26
- 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.13.0-dev.
|
|
3
|
+
"version": "0.13.0-dev.30",
|
|
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.13.0-dev.
|
|
10
|
-
"@prisma-next/contract": "0.13.0-dev.
|
|
11
|
-
"@prisma-next/contract-authoring": "0.13.0-dev.
|
|
12
|
-
"@prisma-next/framework-components": "0.13.0-dev.
|
|
13
|
-
"@prisma-next/sql-contract": "0.13.0-dev.
|
|
14
|
-
"@prisma-next/utils": "0.13.0-dev.
|
|
9
|
+
"@prisma-next/config": "0.13.0-dev.30",
|
|
10
|
+
"@prisma-next/contract": "0.13.0-dev.30",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.13.0-dev.30",
|
|
12
|
+
"@prisma-next/framework-components": "0.13.0-dev.30",
|
|
13
|
+
"@prisma-next/sql-contract": "0.13.0-dev.30",
|
|
14
|
+
"@prisma-next/utils": "0.13.0-dev.30",
|
|
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.13.0-dev.
|
|
21
|
-
"@prisma-next/tsconfig": "0.13.0-dev.
|
|
20
|
+
"@prisma-next/test-utils": "0.13.0-dev.30",
|
|
21
|
+
"@prisma-next/tsconfig": "0.13.0-dev.30",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.21.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.13.0-dev.
|
|
24
|
+
"@prisma-next/tsdown": "0.13.0-dev.30",
|
|
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
|
|
|
@@ -322,55 +317,6 @@ function ensureUnboundNamespaceSlot(
|
|
|
322
317
|
});
|
|
323
318
|
}
|
|
324
319
|
|
|
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
320
|
export function buildSqlContractFromDefinition(
|
|
375
321
|
definition: ContractDefinition,
|
|
376
322
|
codecLookup?: CodecLookup,
|
|
@@ -391,7 +337,7 @@ export function buildSqlContractFromDefinition(
|
|
|
391
337
|
definition.models.map((m) => [`${resolveNamespaceId(m)}:${m.modelName}`, m]),
|
|
392
338
|
);
|
|
393
339
|
|
|
394
|
-
const tablesByNamespace: Record<string, Record<string,
|
|
340
|
+
const tablesByNamespace: Record<string, Record<string, StorageTableInput>> = {};
|
|
395
341
|
const modelNameToNamespaceId = new Map<string, string>();
|
|
396
342
|
const executionDefaults: ExecutionMutationDefault[] = [];
|
|
397
343
|
const modelsByNamespace: Record<string, Record<string, ContractModel>> = {};
|
|
@@ -451,9 +397,9 @@ export function buildSqlContractFromDefinition(
|
|
|
451
397
|
enumHandle !== undefined
|
|
452
398
|
? {
|
|
453
399
|
plane: 'storage',
|
|
454
|
-
entityKind: '
|
|
400
|
+
entityKind: 'valueSet',
|
|
455
401
|
namespaceId: defaultNamespaceId,
|
|
456
|
-
|
|
402
|
+
entityName: enumHandle.enumName,
|
|
457
403
|
}
|
|
458
404
|
: undefined;
|
|
459
405
|
const domainValueSetRef: ValueSetRef | undefined =
|
|
@@ -462,7 +408,7 @@ export function buildSqlContractFromDefinition(
|
|
|
462
408
|
plane: 'domain',
|
|
463
409
|
entityKind: 'enum',
|
|
464
410
|
namespaceId: defaultNamespaceId,
|
|
465
|
-
|
|
411
|
+
entityName: enumHandle.enumName,
|
|
466
412
|
}
|
|
467
413
|
: undefined;
|
|
468
414
|
|
|
@@ -604,7 +550,7 @@ export function buildSqlContractFromDefinition(
|
|
|
604
550
|
`buildSqlContractFromDefinition: duplicate table "${tableName}" in namespace "${namespaceId}".`,
|
|
605
551
|
);
|
|
606
552
|
}
|
|
607
|
-
nsTables[tableName] =
|
|
553
|
+
nsTables[tableName] = tableInput;
|
|
608
554
|
}
|
|
609
555
|
|
|
610
556
|
// --- Build contract model ---
|
|
@@ -725,13 +671,9 @@ export function buildSqlContractFromDefinition(
|
|
|
725
671
|
// discriminator shape before hashing so the storageHash matches the
|
|
726
672
|
// persisted JSON envelope produced from the SqlStorage class instance
|
|
727
673
|
// (which always carries the discriminator).
|
|
728
|
-
const rawStorageTypes =
|
|
729
|
-
|
|
730
|
-
StorageTypeInstance | PostgresEnumStorageEntry
|
|
731
|
-
>;
|
|
732
|
-
const storageTypes = Object.fromEntries(
|
|
674
|
+
const rawStorageTypes = definition.storageTypes ?? {};
|
|
675
|
+
const documentTypes: Record<string, StorageTypeInstance> = Object.fromEntries(
|
|
733
676
|
Object.entries(rawStorageTypes).map(([name, entry]) => {
|
|
734
|
-
if (isPostgresEnumStorageEntry(entry)) return [name, entry];
|
|
735
677
|
if ((entry as { kind?: unknown }).kind === 'codec-instance') return [name, entry];
|
|
736
678
|
return [
|
|
737
679
|
name,
|
|
@@ -743,15 +685,7 @@ export function buildSqlContractFromDefinition(
|
|
|
743
685
|
];
|
|
744
686
|
}),
|
|
745
687
|
);
|
|
746
|
-
const { documentTypes, namespaceEnumTypesById } = partitionStorageTypesForTarget(
|
|
747
|
-
target,
|
|
748
|
-
storageTypes,
|
|
749
|
-
definition.namespaceTypes,
|
|
750
|
-
);
|
|
751
688
|
const namespaceCoordinateIds = collectStorageNamespaceCoordinateIds(definition);
|
|
752
|
-
for (const id of Object.keys(namespaceEnumTypesById)) {
|
|
753
|
-
namespaceCoordinateIds.add(id);
|
|
754
|
-
}
|
|
755
689
|
|
|
756
690
|
// Build per-namespace registries for `enumType()` handles.
|
|
757
691
|
// All authored enums target the contract's default namespace.
|
|
@@ -771,7 +705,10 @@ export function buildSqlContractFromDefinition(
|
|
|
771
705
|
}
|
|
772
706
|
domainSlot[enumName] = {
|
|
773
707
|
codecId: handle.codecId,
|
|
774
|
-
members: handle.enumMembers
|
|
708
|
+
members: handle.enumMembers.map((m) => ({
|
|
709
|
+
name: m.name,
|
|
710
|
+
value: encodeViaCodec(m.value, handle.codecId, codecLookup),
|
|
711
|
+
})),
|
|
775
712
|
};
|
|
776
713
|
|
|
777
714
|
let storageSlot = storageValueSetsByNs[nsId];
|
|
@@ -780,8 +717,8 @@ export function buildSqlContractFromDefinition(
|
|
|
780
717
|
storageValueSetsByNs[nsId] = storageSlot;
|
|
781
718
|
}
|
|
782
719
|
storageSlot[enumName] = {
|
|
783
|
-
kind: '
|
|
784
|
-
values: handle.values,
|
|
720
|
+
kind: 'valueSet',
|
|
721
|
+
values: handle.values.map((v) => encodeViaCodec(v, handle.codecId, codecLookup)),
|
|
785
722
|
};
|
|
786
723
|
}
|
|
787
724
|
|
|
@@ -792,7 +729,6 @@ export function buildSqlContractFromDefinition(
|
|
|
792
729
|
>(
|
|
793
730
|
Object.fromEntries(
|
|
794
731
|
[...namespaceCoordinateIds].sort().map((id) => {
|
|
795
|
-
const enumTypes = namespaceEnumTypesById[id];
|
|
796
732
|
const valueSetEntries = storageValueSetsByNs[id];
|
|
797
733
|
const nsInput: SqlNamespaceTablesInput = {
|
|
798
734
|
id,
|
|
@@ -803,10 +739,7 @@ export function buildSqlContractFromDefinition(
|
|
|
803
739
|
: {}),
|
|
804
740
|
},
|
|
805
741
|
};
|
|
806
|
-
return [
|
|
807
|
-
id,
|
|
808
|
-
createNamespace ? createNamespace(nsInput, enumTypes) : buildSqlNamespace(nsInput),
|
|
809
|
-
];
|
|
742
|
+
return [id, createNamespace ? createNamespace(nsInput) : buildSqlNamespace(nsInput)];
|
|
810
743
|
}),
|
|
811
744
|
),
|
|
812
745
|
);
|
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,
|
|
@@ -162,33 +161,14 @@ export interface ContractDefinition {
|
|
|
162
161
|
readonly extensionPacks?: Record<string, ExtensionPackRef<'sql', string>>;
|
|
163
162
|
readonly storageHash?: string;
|
|
164
163
|
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
|
-
>;
|
|
164
|
+
readonly storageTypes?: Record<string, StorageTypeInstance>;
|
|
175
165
|
/**
|
|
176
166
|
* Declared namespace coordinates for this contract — populates
|
|
177
167
|
* `SqlStorage.namespaces` together with `createNamespace`.
|
|
178
168
|
*/
|
|
179
169
|
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;
|
|
170
|
+
/** Target-supplied factory that materialises a `Namespace` concretion for a declared namespace coordinate. */
|
|
171
|
+
readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
|
|
192
172
|
readonly models: readonly ModelNode[];
|
|
193
173
|
readonly valueObjects?: readonly ValueObjectNode[];
|
|
194
174
|
/**
|
package/src/contract-dsl.ts
CHANGED
|
@@ -16,11 +16,7 @@ import type {
|
|
|
16
16
|
TargetPackRef,
|
|
17
17
|
} from '@prisma-next/framework-components/components';
|
|
18
18
|
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
19
|
-
import type {
|
|
20
|
-
PostgresEnumStorageEntry,
|
|
21
|
-
SqlNamespaceTablesInput,
|
|
22
|
-
StorageTypeInstance,
|
|
23
|
-
} from '@prisma-next/sql-contract/types';
|
|
19
|
+
import type { SqlNamespaceTablesInput, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
24
20
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
25
21
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
26
22
|
import type { NamedConstraintSpec } from './authoring-type-utils';
|
|
@@ -34,7 +30,7 @@ export type NamingConfig = {
|
|
|
34
30
|
readonly columns?: NamingStrategy;
|
|
35
31
|
};
|
|
36
32
|
|
|
37
|
-
type NamedStorageTypeRef = string | StorageTypeInstance |
|
|
33
|
+
type NamedStorageTypeRef = string | StorageTypeInstance | EnumTypeHandle;
|
|
38
34
|
|
|
39
35
|
type NamedConstraintNameSpec<Name extends string = string> = {
|
|
40
36
|
readonly name: Name;
|
|
@@ -338,6 +334,36 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
338
334
|
}
|
|
339
335
|
}
|
|
340
336
|
|
|
337
|
+
export class EnumScalarFieldBuilder<
|
|
338
|
+
Handle extends EnumTypeHandle,
|
|
339
|
+
State extends AnyScalarFieldState = ScalarFieldState<Handle['codecId'], Handle, false, undefined>,
|
|
340
|
+
> extends ScalarFieldBuilder<State> {
|
|
341
|
+
readonly #handle: Handle;
|
|
342
|
+
|
|
343
|
+
constructor(state: State, handle: Handle) {
|
|
344
|
+
super(state);
|
|
345
|
+
this.#handle = handle;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
override default(value: Handle['values'][number]): EnumScalarFieldBuilder<Handle, State> {
|
|
349
|
+
return blindCast<
|
|
350
|
+
EnumScalarFieldBuilder<Handle, State>,
|
|
351
|
+
'object spread does not narrow the generic State conditional; runtime shape is correct'
|
|
352
|
+
>(
|
|
353
|
+
new EnumScalarFieldBuilder(
|
|
354
|
+
{ ...this.build(), default: { kind: 'literal', value } },
|
|
355
|
+
this.#handle,
|
|
356
|
+
),
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
override defaultSql(_expression: never): never {
|
|
361
|
+
throw new Error(
|
|
362
|
+
'defaultSql is not available on an enum field; use .default(members.X) instead',
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
341
367
|
function columnField<Descriptor extends ColumnTypeDescriptor>(
|
|
342
368
|
descriptor: Descriptor,
|
|
343
369
|
): ScalarFieldBuilder<ScalarFieldState<Descriptor['codecId'], undefined, false, undefined>> {
|
|
@@ -368,21 +394,19 @@ function namedTypeField<TypeRef extends string>(
|
|
|
368
394
|
function namedTypeField<TypeRef extends StorageTypeInstance>(
|
|
369
395
|
typeRef: TypeRef,
|
|
370
396
|
): ScalarFieldBuilder<ScalarFieldState<TypeRef['codecId'], TypeRef, false, undefined>>;
|
|
371
|
-
function namedTypeField<TypeRef extends PostgresEnumStorageEntry>(
|
|
372
|
-
typeRef: TypeRef,
|
|
373
|
-
): ScalarFieldBuilder<ScalarFieldState<string, TypeRef, false, undefined>>;
|
|
374
397
|
function namedTypeField<Handle extends EnumTypeHandle>(
|
|
375
398
|
typeRef: Handle,
|
|
376
|
-
):
|
|
377
|
-
function namedTypeField(
|
|
378
|
-
typeRef: NamedStorageTypeRef,
|
|
379
|
-
): ScalarFieldBuilder<ScalarFieldState<string, NamedStorageTypeRef, false, undefined>> {
|
|
399
|
+
): EnumScalarFieldBuilder<Handle>;
|
|
400
|
+
function namedTypeField(typeRef: NamedStorageTypeRef): ScalarFieldBuilder {
|
|
380
401
|
if (isEnumTypeHandle(typeRef)) {
|
|
381
|
-
return new
|
|
382
|
-
|
|
402
|
+
return new EnumScalarFieldBuilder(
|
|
403
|
+
{
|
|
404
|
+
kind: 'scalar',
|
|
405
|
+
typeRef,
|
|
406
|
+
nullable: false,
|
|
407
|
+
},
|
|
383
408
|
typeRef,
|
|
384
|
-
|
|
385
|
-
});
|
|
409
|
+
);
|
|
386
410
|
}
|
|
387
411
|
return new ScalarFieldBuilder({
|
|
388
412
|
kind: 'scalar',
|