@prisma-next/sql-contract-ts 0.16.0-dev.20 → 0.16.0-dev.22
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 +1 -1
- package/dist/{build-contract-DWRZ3jRz.mjs → build-contract-Drz7JW70.mjs} +9 -9
- package/dist/build-contract-Drz7JW70.mjs.map +1 -0
- package/dist/config-types.mjs +4 -4
- package/dist/config-types.mjs.map +1 -1
- package/dist/contract-builder.d.mts +27 -27
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +26 -26
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +10 -10
- package/schemas/data-contract-sql-v1.json +1 -1
- package/src/build-contract.ts +11 -11
- package/src/composed-authoring-helpers.ts +19 -19
- package/src/config-types.ts +3 -3
- package/src/contract-builder.ts +22 -26
- package/src/contract-definition.ts +1 -1
- package/src/contract-dsl.ts +2 -2
- package/src/contract-lowering.ts +18 -18
- package/src/contract-types.ts +7 -7
- package/dist/build-contract-DWRZ3jRz.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.16.0-dev.
|
|
3
|
+
"version": "0.16.0-dev.22",
|
|
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.16.0-dev.
|
|
10
|
-
"@prisma-next/contract": "0.16.0-dev.
|
|
11
|
-
"@prisma-next/contract-authoring": "0.16.0-dev.
|
|
12
|
-
"@prisma-next/framework-components": "0.16.0-dev.
|
|
13
|
-
"@prisma-next/sql-contract": "0.16.0-dev.
|
|
14
|
-
"@prisma-next/utils": "0.16.0-dev.
|
|
9
|
+
"@prisma-next/config": "0.16.0-dev.22",
|
|
10
|
+
"@prisma-next/contract": "0.16.0-dev.22",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.16.0-dev.22",
|
|
12
|
+
"@prisma-next/framework-components": "0.16.0-dev.22",
|
|
13
|
+
"@prisma-next/sql-contract": "0.16.0-dev.22",
|
|
14
|
+
"@prisma-next/utils": "0.16.0-dev.22",
|
|
15
15
|
"arktype": "^2.2.2",
|
|
16
16
|
"pathe": "^2.0.3",
|
|
17
17
|
"ts-toolbelt": "^9.6.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@prisma-next/test-utils": "0.16.0-dev.
|
|
21
|
-
"@prisma-next/tsconfig": "0.16.0-dev.
|
|
20
|
+
"@prisma-next/test-utils": "0.16.0-dev.22",
|
|
21
|
+
"@prisma-next/tsconfig": "0.16.0-dev.22",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.22.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.16.0-dev.
|
|
24
|
+
"@prisma-next/tsdown": "0.16.0-dev.22",
|
|
25
25
|
"tsdown": "0.22.8",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.10"
|
package/src/build-contract.ts
CHANGED
|
@@ -126,7 +126,7 @@ function assertStorageSemantics(
|
|
|
126
126
|
const indexTypeRegistry = createIndexTypeRegistry();
|
|
127
127
|
const packsToRegister: ReadonlyArray<{ readonly id?: string; readonly indexTypes?: unknown }> = [
|
|
128
128
|
definition.target,
|
|
129
|
-
...Object.values(definition.
|
|
129
|
+
...Object.values(definition.extensions ?? {}),
|
|
130
130
|
];
|
|
131
131
|
for (const pack of packsToRegister) {
|
|
132
132
|
const registration = pack.indexTypes;
|
|
@@ -557,7 +557,7 @@ function assertNoManagedEntityKinds(
|
|
|
557
557
|
* the same string a pack entity's entries-map key (`entries.<kind>`) uses.
|
|
558
558
|
* Mirrors `contract-psl`'s `buildEntityTypesByDiscriminator`, recomposed here
|
|
559
559
|
* from the packs `ContractDefinition` already carries (`target` +
|
|
560
|
-
* `
|
|
560
|
+
* `extensions`) since the TS assembler has no single pre-merged
|
|
561
561
|
* `AuthoringContributions` input to read the way the PSL interpreter does.
|
|
562
562
|
*/
|
|
563
563
|
function collectEntityTypeDescriptorsByDiscriminator(
|
|
@@ -573,7 +573,7 @@ function collectEntityTypeDescriptorsByDiscriminator(
|
|
|
573
573
|
}
|
|
574
574
|
}
|
|
575
575
|
};
|
|
576
|
-
const components = [definition.target, ...Object.values(definition.
|
|
576
|
+
const components = [definition.target, ...Object.values(definition.extensions ?? {})];
|
|
577
577
|
for (const component of components) {
|
|
578
578
|
const entityTypes = component.authoring?.entityTypes;
|
|
579
579
|
if (entityTypes !== undefined) {
|
|
@@ -1219,21 +1219,21 @@ export function buildSqlContractFromDefinition(
|
|
|
1219
1219
|
}
|
|
1220
1220
|
: undefined;
|
|
1221
1221
|
|
|
1222
|
-
const extensionNamespaces = definition.
|
|
1223
|
-
? Object.values(definition.
|
|
1222
|
+
const extensionNamespaces = definition.extensions
|
|
1223
|
+
? Object.values(definition.extensions).map((pack) => pack.id)
|
|
1224
1224
|
: undefined;
|
|
1225
1225
|
|
|
1226
|
-
const
|
|
1226
|
+
const extensions: Record<string, unknown> = { ...(definition.extensions || {}) };
|
|
1227
1227
|
if (extensionNamespaces) {
|
|
1228
1228
|
for (const namespace of extensionNamespaces) {
|
|
1229
|
-
if (!Object.hasOwn(
|
|
1230
|
-
|
|
1229
|
+
if (!Object.hasOwn(extensions, namespace)) {
|
|
1230
|
+
extensions[namespace] = {};
|
|
1231
1231
|
}
|
|
1232
1232
|
}
|
|
1233
1233
|
}
|
|
1234
1234
|
|
|
1235
|
-
const extensionPackCapabilitySources = definition.
|
|
1236
|
-
? Object.values(definition.
|
|
1235
|
+
const extensionPackCapabilitySources = definition.extensions
|
|
1236
|
+
? Object.values(definition.extensions).map(
|
|
1237
1237
|
(pack) => pack.capabilities as CapabilityMatrix | undefined,
|
|
1238
1238
|
)
|
|
1239
1239
|
: [];
|
|
@@ -1323,7 +1323,7 @@ export function buildSqlContractFromDefinition(
|
|
|
1323
1323
|
roots,
|
|
1324
1324
|
storage,
|
|
1325
1325
|
...(executionWithHash ? { execution: executionWithHash } : {}),
|
|
1326
|
-
|
|
1326
|
+
extensions,
|
|
1327
1327
|
capabilities,
|
|
1328
1328
|
profileHash,
|
|
1329
1329
|
meta: {},
|
|
@@ -56,16 +56,16 @@ type ExtractEntitiesNamespaceFromPack<Pack> = ExtractAuthoringNamespaceFromPack<
|
|
|
56
56
|
Record<never, never>
|
|
57
57
|
>;
|
|
58
58
|
|
|
59
|
-
type MergeExtensionTypeNamespaces<
|
|
60
|
-
|
|
59
|
+
type MergeExtensionTypeNamespaces<Extensions> = MergeExtensionAuthoringNamespaces<
|
|
60
|
+
Extensions,
|
|
61
61
|
'type'
|
|
62
62
|
>;
|
|
63
|
-
type MergeExtensionFieldNamespaces<
|
|
64
|
-
|
|
63
|
+
type MergeExtensionFieldNamespaces<Extensions> = MergeExtensionAuthoringNamespaces<
|
|
64
|
+
Extensions,
|
|
65
65
|
'field'
|
|
66
66
|
>;
|
|
67
|
-
type MergeExtensionEntityNamespaces<
|
|
68
|
-
|
|
67
|
+
type MergeExtensionEntityNamespaces<Extensions> = MergeExtensionAuthoringNamespaces<
|
|
68
|
+
Extensions,
|
|
69
69
|
'entityTypes'
|
|
70
70
|
>;
|
|
71
71
|
|
|
@@ -101,12 +101,12 @@ type TypeHelpersFromNamespace<Namespace> = {
|
|
|
101
101
|
|
|
102
102
|
type CoreFieldHelpers = Pick<typeof field, 'column' | 'generated' | 'namedType'>;
|
|
103
103
|
|
|
104
|
-
type MergeAllPackIndexTypes<Family, Target,
|
|
105
|
-
{ readonly __family: Family; readonly __target: Target } & (
|
|
104
|
+
type MergeAllPackIndexTypes<Family, Target, Extensions> = MergeExtensionIndexTypes<
|
|
105
|
+
{ readonly __family: Family; readonly __target: Target } & (Extensions extends Record<
|
|
106
106
|
string,
|
|
107
107
|
unknown
|
|
108
108
|
>
|
|
109
|
-
?
|
|
109
|
+
? Extensions
|
|
110
110
|
: Record<never, never>)
|
|
111
111
|
>;
|
|
112
112
|
|
|
@@ -132,24 +132,24 @@ type PackAwareModel<IndexTypes extends IndexTypeMap> = {
|
|
|
132
132
|
export type ComposedAuthoringHelpers<
|
|
133
133
|
Family extends FamilyPackRef<string>,
|
|
134
134
|
Target extends TargetPackRef<'sql', string>,
|
|
135
|
-
|
|
135
|
+
Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
136
136
|
> = EntityHelpersFromNamespace<
|
|
137
137
|
ExtractEntitiesNamespaceFromPack<Family> &
|
|
138
138
|
ExtractEntitiesNamespaceFromPack<Target> &
|
|
139
|
-
MergeExtensionEntityNamespaces<
|
|
139
|
+
MergeExtensionEntityNamespaces<Extensions>
|
|
140
140
|
> & {
|
|
141
141
|
readonly field: CoreFieldHelpers &
|
|
142
142
|
FieldHelpersFromNamespace<
|
|
143
143
|
ExtractFieldNamespaceFromPack<Family> &
|
|
144
144
|
ExtractFieldNamespaceFromPack<Target> &
|
|
145
|
-
MergeExtensionFieldNamespaces<
|
|
145
|
+
MergeExtensionFieldNamespaces<Extensions>
|
|
146
146
|
>;
|
|
147
|
-
readonly model: PackAwareModel<MergeAllPackIndexTypes<Family, Target,
|
|
147
|
+
readonly model: PackAwareModel<MergeAllPackIndexTypes<Family, Target, Extensions>>;
|
|
148
148
|
readonly rel: typeof rel;
|
|
149
149
|
readonly type: TypeHelpersFromNamespace<
|
|
150
150
|
ExtractTypeNamespaceFromPack<Family> &
|
|
151
151
|
ExtractTypeNamespaceFromPack<Target> &
|
|
152
|
-
MergeExtensionTypeNamespaces<
|
|
152
|
+
MergeExtensionTypeNamespaces<Extensions>
|
|
153
153
|
>;
|
|
154
154
|
};
|
|
155
155
|
|
|
@@ -272,14 +272,14 @@ function createComposedFieldHelpers(
|
|
|
272
272
|
export function createComposedAuthoringHelpers<
|
|
273
273
|
Family extends FamilyPackRef<string>,
|
|
274
274
|
Target extends TargetPackRef<'sql', string>,
|
|
275
|
-
|
|
275
|
+
Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
276
276
|
>(options: {
|
|
277
277
|
readonly family: Family;
|
|
278
278
|
readonly target: Target;
|
|
279
|
-
readonly
|
|
280
|
-
}): ComposedAuthoringHelpers<Family, Target,
|
|
279
|
+
readonly extensions?: Extensions;
|
|
280
|
+
}): ComposedAuthoringHelpers<Family, Target, Extensions> {
|
|
281
281
|
const extensionValues: readonly ExtensionPackRef<'sql', string>[] = Object.values(
|
|
282
|
-
(options.
|
|
282
|
+
(options.extensions ?? {}) as Record<string, ExtensionPackRef<'sql', string>>,
|
|
283
283
|
);
|
|
284
284
|
const components: readonly AuthoringComponent[] = [
|
|
285
285
|
options.family,
|
|
@@ -303,5 +303,5 @@ export function createComposedAuthoringHelpers<
|
|
|
303
303
|
model,
|
|
304
304
|
rel,
|
|
305
305
|
type: createTypeHelpersFromNamespace(typeNamespace),
|
|
306
|
-
} as ComposedAuthoringHelpers<Family, Target,
|
|
306
|
+
} as ComposedAuthoringHelpers<Family, Target, Extensions>;
|
|
307
307
|
}
|
package/src/config-types.ts
CHANGED
|
@@ -35,7 +35,7 @@ export function emptyContract(options: {
|
|
|
35
35
|
}): ContractConfig {
|
|
36
36
|
return {
|
|
37
37
|
source: {
|
|
38
|
-
|
|
38
|
+
format: 'typescript',
|
|
39
39
|
load: async () => {
|
|
40
40
|
const built = buildSqlContractFromDefinition({
|
|
41
41
|
target: options.target,
|
|
@@ -56,7 +56,7 @@ export function typescriptContract(
|
|
|
56
56
|
): ContractConfig {
|
|
57
57
|
return {
|
|
58
58
|
source: {
|
|
59
|
-
|
|
59
|
+
format: 'typescript',
|
|
60
60
|
load: async () =>
|
|
61
61
|
ok(applySpecifierDefaultControlPolicy(contract, options?.defaultControlPolicy)),
|
|
62
62
|
},
|
|
@@ -73,7 +73,7 @@ export function typescriptContractFromPath(
|
|
|
73
73
|
): ContractConfig {
|
|
74
74
|
return {
|
|
75
75
|
source: {
|
|
76
|
-
|
|
76
|
+
format: 'typescript',
|
|
77
77
|
inputs: [contractPath],
|
|
78
78
|
load: async (context) => {
|
|
79
79
|
const [absolutePath] = context.resolvedInputs;
|
package/src/contract-builder.ts
CHANGED
|
@@ -58,7 +58,7 @@ type ContractDefinition<
|
|
|
58
58
|
Target extends TargetPackRef<'sql', string>,
|
|
59
59
|
Types extends Record<string, StorageTypeInstance>,
|
|
60
60
|
Models extends Record<string, ModelLike>,
|
|
61
|
-
|
|
61
|
+
Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
62
62
|
Naming extends ContractInput['naming'] | undefined,
|
|
63
63
|
StorageHash extends string | undefined,
|
|
64
64
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
@@ -67,7 +67,7 @@ type ContractDefinition<
|
|
|
67
67
|
> = {
|
|
68
68
|
readonly family: Family;
|
|
69
69
|
readonly target: Target;
|
|
70
|
-
readonly
|
|
70
|
+
readonly extensions?: Extensions;
|
|
71
71
|
readonly naming?: Naming;
|
|
72
72
|
readonly storageHash?: StorageHash;
|
|
73
73
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
@@ -84,7 +84,7 @@ type ContractDefinition<
|
|
|
84
84
|
type ContractScaffold<
|
|
85
85
|
Family extends FamilyPackRef<string>,
|
|
86
86
|
Target extends TargetPackRef<'sql', string>,
|
|
87
|
-
|
|
87
|
+
Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
88
88
|
Naming extends ContractInput['naming'] | undefined,
|
|
89
89
|
StorageHash extends string | undefined,
|
|
90
90
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
@@ -93,7 +93,7 @@ type ContractScaffold<
|
|
|
93
93
|
> = {
|
|
94
94
|
readonly family: Family;
|
|
95
95
|
readonly target: Target;
|
|
96
|
-
readonly
|
|
96
|
+
readonly extensions?: Extensions;
|
|
97
97
|
readonly naming?: Naming;
|
|
98
98
|
readonly storageHash?: StorageHash;
|
|
99
99
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
@@ -112,9 +112,9 @@ type ContractFactory<
|
|
|
112
112
|
Target extends TargetPackRef<'sql', string>,
|
|
113
113
|
Types extends Record<string, StorageTypeInstance>,
|
|
114
114
|
Models extends Record<string, ModelLike>,
|
|
115
|
-
|
|
115
|
+
Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
116
116
|
Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
117
|
-
> = (helpers: ComposedAuthoringHelpers<Family, Target,
|
|
117
|
+
> = (helpers: ComposedAuthoringHelpers<Family, Target, Extensions>) => {
|
|
118
118
|
readonly types?: Types;
|
|
119
119
|
readonly models?: Models;
|
|
120
120
|
readonly enums?: Enums;
|
|
@@ -296,17 +296,17 @@ function validatePerModelNamespaces(
|
|
|
296
296
|
|
|
297
297
|
function validateExtensionPackRefs(
|
|
298
298
|
target: TargetPackRef<'sql', string>,
|
|
299
|
-
|
|
299
|
+
extensions?: Record<string, ExtensionPackRef<'sql', string>>,
|
|
300
300
|
): void {
|
|
301
|
-
if (!
|
|
301
|
+
if (!extensions) {
|
|
302
302
|
return;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
for (const packRef of Object.values(
|
|
305
|
+
for (const packRef of Object.values(extensions)) {
|
|
306
306
|
if (packRef.kind !== 'extension') {
|
|
307
307
|
throw contractError(
|
|
308
308
|
'CONTRACT.PACK_REF_INVALID',
|
|
309
|
-
`defineContract only accepts extension pack refs in
|
|
309
|
+
`defineContract only accepts extension pack refs in extensions. Received kind "${packRef.kind}".`,
|
|
310
310
|
{ meta: { packId: packRef.id, kind: packRef.kind } },
|
|
311
311
|
);
|
|
312
312
|
}
|
|
@@ -345,7 +345,7 @@ function buildContractFromDsl<Definition extends ContractInput>(
|
|
|
345
345
|
definition: Definition,
|
|
346
346
|
): SqlContractResult<Definition> {
|
|
347
347
|
validateTargetPackRef(definition.family, definition.target);
|
|
348
|
-
validateExtensionPackRefs(definition.target, definition.
|
|
348
|
+
validateExtensionPackRefs(definition.target, definition.extensions);
|
|
349
349
|
validateNamespaceDeclarations(definition.target, definition.namespaces);
|
|
350
350
|
validatePerModelNamespaces(
|
|
351
351
|
definition.target,
|
|
@@ -364,13 +364,13 @@ function buildContractFromDsl<Definition extends ContractInput>(
|
|
|
364
364
|
type BoundDefinitionInput<
|
|
365
365
|
Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
366
366
|
Models extends Record<string, ModelLike> = Record<never, never>,
|
|
367
|
-
|
|
367
|
+
Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined = undefined,
|
|
368
368
|
Naming extends ContractInput['naming'] | undefined = undefined,
|
|
369
369
|
StorageHash extends string | undefined = undefined,
|
|
370
370
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
371
371
|
Namespaces extends readonly string[] | undefined = undefined,
|
|
372
372
|
> = {
|
|
373
|
-
readonly
|
|
373
|
+
readonly extensions?: Extensions;
|
|
374
374
|
readonly naming?: Naming;
|
|
375
375
|
readonly storageHash?: StorageHash;
|
|
376
376
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
@@ -457,7 +457,7 @@ export function buildBoundContract<
|
|
|
457
457
|
target: T,
|
|
458
458
|
definition: Definition,
|
|
459
459
|
factory: (
|
|
460
|
-
helpers: ComposedAuthoringHelpers<F, T, NonNullable<Definition['
|
|
460
|
+
helpers: ComposedAuthoringHelpers<F, T, NonNullable<Definition['extensions']>>,
|
|
461
461
|
) => Built,
|
|
462
462
|
): SqlContractResult<WithFamilyTarget<Definition & Built, F, T>>;
|
|
463
463
|
/** Implementation. */
|
|
@@ -487,7 +487,7 @@ export function buildBoundContract(
|
|
|
487
487
|
createComposedAuthoringHelpers({
|
|
488
488
|
family,
|
|
489
489
|
target,
|
|
490
|
-
|
|
490
|
+
extensions: definition.extensions,
|
|
491
491
|
}),
|
|
492
492
|
);
|
|
493
493
|
const mergedEnums = { ...(definition.enums ?? {}), ...built.enums };
|
|
@@ -509,9 +509,7 @@ export function defineContract<
|
|
|
509
509
|
const Target extends TargetPackRef<'sql', string>,
|
|
510
510
|
const Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
511
511
|
const Models extends Record<string, ModelLike> = Record<never, never>,
|
|
512
|
-
const
|
|
513
|
-
| Record<string, ExtensionPackRef<'sql', string>>
|
|
514
|
-
| undefined = undefined,
|
|
512
|
+
const Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined = undefined,
|
|
515
513
|
const Naming extends ContractInput['naming'] | undefined = undefined,
|
|
516
514
|
const StorageHash extends string | undefined = undefined,
|
|
517
515
|
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
@@ -523,7 +521,7 @@ export function defineContract<
|
|
|
523
521
|
Target,
|
|
524
522
|
Types,
|
|
525
523
|
Models,
|
|
526
|
-
|
|
524
|
+
Extensions,
|
|
527
525
|
Naming,
|
|
528
526
|
StorageHash,
|
|
529
527
|
ForeignKeyDefaults,
|
|
@@ -536,7 +534,7 @@ export function defineContract<
|
|
|
536
534
|
Target,
|
|
537
535
|
Types,
|
|
538
536
|
Models,
|
|
539
|
-
|
|
537
|
+
Extensions,
|
|
540
538
|
Naming,
|
|
541
539
|
StorageHash,
|
|
542
540
|
ForeignKeyDefaults,
|
|
@@ -549,9 +547,7 @@ export function defineContract<
|
|
|
549
547
|
const Target extends TargetPackRef<'sql', string>,
|
|
550
548
|
const Types extends Record<string, StorageTypeInstance> = Record<never, never>,
|
|
551
549
|
const Models extends Record<string, ModelLike> = Record<never, never>,
|
|
552
|
-
const
|
|
553
|
-
| Record<string, ExtensionPackRef<'sql', string>>
|
|
554
|
-
| undefined = undefined,
|
|
550
|
+
const Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined = undefined,
|
|
555
551
|
const Naming extends ContractInput['naming'] | undefined = undefined,
|
|
556
552
|
const StorageHash extends string | undefined = undefined,
|
|
557
553
|
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
@@ -562,21 +558,21 @@ export function defineContract<
|
|
|
562
558
|
definition: ContractScaffold<
|
|
563
559
|
Family,
|
|
564
560
|
Target,
|
|
565
|
-
|
|
561
|
+
Extensions,
|
|
566
562
|
Naming,
|
|
567
563
|
StorageHash,
|
|
568
564
|
ForeignKeyDefaults,
|
|
569
565
|
Namespaces,
|
|
570
566
|
ScaffoldEnums
|
|
571
567
|
>,
|
|
572
|
-
factory: ContractFactory<Family, Target, Types, Models,
|
|
568
|
+
factory: ContractFactory<Family, Target, Types, Models, Extensions, FactoryEnums>,
|
|
573
569
|
): SqlContractResult<
|
|
574
570
|
ContractDefinition<
|
|
575
571
|
Family,
|
|
576
572
|
Target,
|
|
577
573
|
Types,
|
|
578
574
|
Models,
|
|
579
|
-
|
|
575
|
+
Extensions,
|
|
580
576
|
Naming,
|
|
581
577
|
StorageHash,
|
|
582
578
|
ForeignKeyDefaults,
|
|
@@ -183,7 +183,7 @@ export interface ModelNode {
|
|
|
183
183
|
export interface ContractDefinition {
|
|
184
184
|
readonly target: TargetPackRef<'sql', string>;
|
|
185
185
|
readonly defaultControlPolicy?: ControlPolicy;
|
|
186
|
-
readonly
|
|
186
|
+
readonly extensions?: Record<string, ExtensionPackRef<'sql', string>>;
|
|
187
187
|
readonly storageHash?: string;
|
|
188
188
|
readonly foreignKeyDefaults?: ForeignKeyDefaultsState;
|
|
189
189
|
readonly storageTypes?: Record<string, StorageTypeInstance>;
|
package/src/contract-dsl.ts
CHANGED
|
@@ -1598,11 +1598,11 @@ export type ContractInput<
|
|
|
1598
1598
|
SqlStageSpec | undefined
|
|
1599
1599
|
>
|
|
1600
1600
|
> = Record<never, never>,
|
|
1601
|
-
|
|
1601
|
+
Extensions extends Record<string, ExtensionPackRef<'sql', string>> | undefined = undefined,
|
|
1602
1602
|
> = {
|
|
1603
1603
|
readonly family: Family;
|
|
1604
1604
|
readonly target: Target;
|
|
1605
|
-
readonly
|
|
1605
|
+
readonly extensions?: Extensions;
|
|
1606
1606
|
readonly naming?: NamingConfig;
|
|
1607
1607
|
readonly storageHash?: string;
|
|
1608
1608
|
readonly foreignKeyDefaults?: ForeignKeyDefaultsState;
|
package/src/contract-lowering.ts
CHANGED
|
@@ -392,7 +392,7 @@ function lowerBelongsToRelation(
|
|
|
392
392
|
relation: Extract<RelationState, { kind: 'belongsTo' }>,
|
|
393
393
|
currentSpec: RuntimeModelSpec,
|
|
394
394
|
allSpecs: ReadonlyMap<string, RuntimeModelSpec>,
|
|
395
|
-
|
|
395
|
+
extensions?: Record<string, ExtensionPackRef<'sql', string>>,
|
|
396
396
|
): RelationNode {
|
|
397
397
|
const targetModelName = resolveRelationModelName(relation.toModel);
|
|
398
398
|
const fromFields = normalizeRelationFieldNames(relation.from);
|
|
@@ -412,7 +412,7 @@ function lowerBelongsToRelation(
|
|
|
412
412
|
// requiring a local model spec — matching how the FK lowering works.
|
|
413
413
|
if (relation.spaceId !== undefined) {
|
|
414
414
|
assertKnownExtensionPack(
|
|
415
|
-
|
|
415
|
+
extensions,
|
|
416
416
|
relation.spaceId,
|
|
417
417
|
`Relation "${currentSpec.modelName}.${relationName}"`,
|
|
418
418
|
);
|
|
@@ -610,10 +610,10 @@ function resolveRelationNode(
|
|
|
610
610
|
relation: RelationState,
|
|
611
611
|
currentSpec: RuntimeModelSpec,
|
|
612
612
|
allSpecs: ReadonlyMap<string, RuntimeModelSpec>,
|
|
613
|
-
|
|
613
|
+
extensions?: Record<string, ExtensionPackRef<'sql', string>>,
|
|
614
614
|
): RelationNode {
|
|
615
615
|
if (relation.kind === 'belongsTo') {
|
|
616
|
-
return lowerBelongsToRelation(relationName, relation, currentSpec, allSpecs,
|
|
616
|
+
return lowerBelongsToRelation(relationName, relation, currentSpec, allSpecs, extensions);
|
|
617
617
|
}
|
|
618
618
|
|
|
619
619
|
if (relation.kind === 'hasMany' || relation.kind === 'hasOne') {
|
|
@@ -691,16 +691,16 @@ function lowerCrossSpaceForeignKeyNode(
|
|
|
691
691
|
}
|
|
692
692
|
|
|
693
693
|
function assertKnownExtensionPack(
|
|
694
|
-
|
|
694
|
+
extensions: Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
695
695
|
spaceId: string,
|
|
696
696
|
context: string,
|
|
697
697
|
): void {
|
|
698
|
-
if (
|
|
698
|
+
if (extensions !== undefined && Object.hasOwn(extensions, spaceId)) {
|
|
699
699
|
return;
|
|
700
700
|
}
|
|
701
701
|
throw contractError(
|
|
702
702
|
'CONTRACT.PACK_MISSING',
|
|
703
|
-
`${context} references contract space "${spaceId}" but "${spaceId}" is not declared in
|
|
703
|
+
`${context} references contract space "${spaceId}" but "${spaceId}" is not declared in extensions. Add the pack to extensions.`,
|
|
704
704
|
{ meta: { spaceId, context } },
|
|
705
705
|
);
|
|
706
706
|
}
|
|
@@ -708,14 +708,14 @@ function assertKnownExtensionPack(
|
|
|
708
708
|
function resolveForeignKeyNodes(
|
|
709
709
|
spec: RuntimeModelSpec,
|
|
710
710
|
allSpecs: ReadonlyMap<string, RuntimeModelSpec>,
|
|
711
|
-
|
|
711
|
+
extensions?: Record<string, ExtensionPackRef<'sql', string>>,
|
|
712
712
|
): readonly ForeignKeyNode[] {
|
|
713
713
|
const relationForeignKeys = resolveRelationForeignKeys(spec, allSpecs).map((foreignKey) => {
|
|
714
714
|
// F-relfk: relation-derived FKs for cross-space targets carry targetSpaceId;
|
|
715
715
|
// route them through the cross-space path, just like explicit sql() FKs.
|
|
716
716
|
if (foreignKey.targetSpaceId !== undefined) {
|
|
717
717
|
assertKnownExtensionPack(
|
|
718
|
-
|
|
718
|
+
extensions,
|
|
719
719
|
foreignKey.targetSpaceId,
|
|
720
720
|
`Relation-derived foreign key on "${spec.modelName}"`,
|
|
721
721
|
);
|
|
@@ -740,7 +740,7 @@ function resolveForeignKeyNodes(
|
|
|
740
740
|
const sqlForeignKeys = (spec.sqlSpec?.foreignKeys ?? []).map((foreignKey) => {
|
|
741
741
|
if (foreignKey.targetSpaceId !== undefined) {
|
|
742
742
|
assertKnownExtensionPack(
|
|
743
|
-
|
|
743
|
+
extensions,
|
|
744
744
|
foreignKey.targetSpaceId,
|
|
745
745
|
`Foreign key on "${spec.modelName}"`,
|
|
746
746
|
);
|
|
@@ -770,7 +770,7 @@ function resolveModelNode(
|
|
|
770
770
|
allSpecs: ReadonlyMap<string, RuntimeModelSpec>,
|
|
771
771
|
storageTypes: Record<string, StorageTypeInstance>,
|
|
772
772
|
storageTypeReverseLookup: ReadonlyMap<StorageTypeInstance, string>,
|
|
773
|
-
|
|
773
|
+
extensions?: Record<string, ExtensionPackRef<'sql', string>>,
|
|
774
774
|
): ModelNode {
|
|
775
775
|
const fields: FieldNode[] = [];
|
|
776
776
|
|
|
@@ -816,9 +816,9 @@ function resolveModelNode(
|
|
|
816
816
|
...ifDefined('type', index.type),
|
|
817
817
|
...ifDefined('options', index.options),
|
|
818
818
|
})) satisfies readonly IndexNode[];
|
|
819
|
-
const foreignKeys = resolveForeignKeyNodes(spec, allSpecs,
|
|
819
|
+
const foreignKeys = resolveForeignKeyNodes(spec, allSpecs, extensions);
|
|
820
820
|
const relations = Object.entries(spec.relations).map(([relationName, relationBuilder]) =>
|
|
821
|
-
resolveRelationNode(relationName, relationBuilder.build(), spec, allSpecs,
|
|
821
|
+
resolveRelationNode(relationName, relationBuilder.build(), spec, allSpecs, extensions),
|
|
822
822
|
);
|
|
823
823
|
|
|
824
824
|
return {
|
|
@@ -925,7 +925,7 @@ function collectRuntimeModelSpecs(definition: ContractInput): RuntimeCollection
|
|
|
925
925
|
|
|
926
926
|
function lowerModels(
|
|
927
927
|
collection: RuntimeCollection,
|
|
928
|
-
|
|
928
|
+
extensions?: Record<string, ExtensionPackRef<'sql', string>>,
|
|
929
929
|
): readonly ModelNode[] {
|
|
930
930
|
emitTypedCrossModelFallbackWarnings(collection);
|
|
931
931
|
|
|
@@ -936,7 +936,7 @@ function lowerModels(
|
|
|
936
936
|
collection.modelSpecs,
|
|
937
937
|
collection.storageTypes,
|
|
938
938
|
storageTypeReverseLookup,
|
|
939
|
-
|
|
939
|
+
extensions,
|
|
940
940
|
),
|
|
941
941
|
);
|
|
942
942
|
}
|
|
@@ -972,7 +972,7 @@ function lowerPackEntityHandles(
|
|
|
972
972
|
readonly authoring?: import('@prisma-next/framework-components/authoring').AuthoringContributions;
|
|
973
973
|
}[] = [
|
|
974
974
|
definition.target,
|
|
975
|
-
...Object.values<ExtensionPackRef<'sql', string>>(definition.
|
|
975
|
+
...Object.values<ExtensionPackRef<'sql', string>>(definition.extensions ?? {}),
|
|
976
976
|
];
|
|
977
977
|
const owningComponent = new Map<string, (typeof components)[number]>();
|
|
978
978
|
const walkEntityTypes = (
|
|
@@ -1089,13 +1089,13 @@ function lowerPackEntityHandles(
|
|
|
1089
1089
|
|
|
1090
1090
|
export function buildContractDefinition(definition: ContractInput): ContractDefinition {
|
|
1091
1091
|
const collection = collectRuntimeModelSpecs(definition);
|
|
1092
|
-
const models = lowerModels(collection, definition.
|
|
1092
|
+
const models = lowerModels(collection, definition.extensions);
|
|
1093
1093
|
const attachedEntities = lowerPackEntityHandles(definition, collection.modelSpecs);
|
|
1094
1094
|
|
|
1095
1095
|
return {
|
|
1096
1096
|
target: definition.target,
|
|
1097
1097
|
...ifDefined('defaultControlPolicy', definition.defaultControlPolicy),
|
|
1098
|
-
...(definition.
|
|
1098
|
+
...(definition.extensions ? { extensions: definition.extensions } : {}),
|
|
1099
1099
|
...(definition.storageHash ? { storageHash: definition.storageHash } : {}),
|
|
1100
1100
|
...(definition.foreignKeyDefaults ? { foreignKeyDefaults: definition.foreignKeyDefaults } : {}),
|
|
1101
1101
|
...(Object.keys(collection.storageTypes).length > 0
|
package/src/contract-types.ts
CHANGED
|
@@ -67,8 +67,8 @@ export type MergeExtensionPackRefs<
|
|
|
67
67
|
Added extends Record<string, ExtensionPackRef<'sql', string>>,
|
|
68
68
|
> = Existing extends Record<string, unknown> ? Existing & Added : Added;
|
|
69
69
|
|
|
70
|
-
type
|
|
71
|
-
readonly
|
|
70
|
+
type DefinitionExtensions<Definition> = Definition extends {
|
|
71
|
+
readonly extensions?: infer Packs extends Record<string, ExtensionPackRef<'sql', string>>;
|
|
72
72
|
}
|
|
73
73
|
? Packs
|
|
74
74
|
: Record<never, never>;
|
|
@@ -101,7 +101,7 @@ type DerivedCapabilities<Definition> = Defaulted<
|
|
|
101
101
|
ExtractPackCapabilities<DefinitionTarget<Definition>>,
|
|
102
102
|
Record<string, never>
|
|
103
103
|
> &
|
|
104
|
-
MergeExtensionPackCapabilities<
|
|
104
|
+
MergeExtensionPackCapabilities<DefinitionExtensions<Definition>>;
|
|
105
105
|
|
|
106
106
|
type DefinitionTargetId<Definition> = Definition extends {
|
|
107
107
|
readonly target: TargetPackRef<'sql', infer Target>;
|
|
@@ -114,13 +114,13 @@ type Present<T> = Exclude<T, undefined>;
|
|
|
114
114
|
type CodecTypesFromDefinition<Definition> = ExtractCodecTypesFromPack<
|
|
115
115
|
Definition extends { readonly target: infer Target } ? Target : never
|
|
116
116
|
> &
|
|
117
|
-
MergeExtensionCodecTypesSafe<
|
|
117
|
+
MergeExtensionCodecTypesSafe<DefinitionExtensions<Definition>>;
|
|
118
118
|
|
|
119
119
|
type DefinitionTarget<Definition> = Definition extends { readonly target: infer Target }
|
|
120
120
|
? Target
|
|
121
121
|
: never;
|
|
122
122
|
|
|
123
|
-
type AllPacks<Definition> =
|
|
123
|
+
type AllPacks<Definition> = DefinitionExtensions<Definition> & {
|
|
124
124
|
readonly __target: DefinitionTarget<Definition>;
|
|
125
125
|
};
|
|
126
126
|
|
|
@@ -799,9 +799,9 @@ export type SqlContractResult<Definition> = ContractWithTypeMaps<
|
|
|
799
799
|
readonly namespaces: Readonly<Record<string, BuiltDomainNamespace<Definition>>>;
|
|
800
800
|
} & BuiltDomain<Definition>;
|
|
801
801
|
} & {
|
|
802
|
-
readonly
|
|
802
|
+
readonly extensions: keyof DefinitionExtensions<Definition> extends never
|
|
803
803
|
? Record<string, never>
|
|
804
|
-
:
|
|
804
|
+
: DefinitionExtensions<Definition>;
|
|
805
805
|
readonly capabilities: DerivedCapabilities<Definition>;
|
|
806
806
|
readonly enumAccessors: BuiltEnumAccessors<Definition>;
|
|
807
807
|
},
|