@prisma-next/sql-contract-ts 0.11.0-dev.9 → 0.12.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/dist/build-contract-BCYW3_wE.mjs +385 -0
- package/dist/build-contract-BCYW3_wE.mjs.map +1 -0
- package/dist/config-types.d.mts +6 -1
- package/dist/config-types.d.mts.map +1 -1
- package/dist/config-types.mjs +11 -1
- package/dist/config-types.mjs.map +1 -1
- package/dist/contract-builder.d.mts +38 -28
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +6 -354
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +21 -10
- package/src/build-contract.ts +103 -31
- package/src/config-types.ts +14 -0
- package/src/contract-builder.ts +8 -19
- package/src/contract-definition.ts +0 -1
- package/src/contract-dsl.ts +0 -2
- package/src/contract-lowering.ts +0 -1
- package/src/contract-types.ts +61 -26
- package/src/exports/config-types.ts +5 -1
package/package.json
CHANGED
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-contract-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.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.12.0",
|
|
10
|
+
"@prisma-next/contract": "0.12.0",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.12.0",
|
|
12
|
+
"@prisma-next/framework-components": "0.12.0",
|
|
13
|
+
"@prisma-next/sql-contract": "0.12.0",
|
|
14
|
+
"@prisma-next/utils": "0.12.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.12.0",
|
|
21
|
+
"@prisma-next/tsconfig": "0.12.0",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.20.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.
|
|
24
|
+
"@prisma-next/tsdown": "0.12.0",
|
|
25
25
|
"tsdown": "0.22.0",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.6"
|
|
28
28
|
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"typescript": ">=5.9"
|
|
31
|
+
},
|
|
32
|
+
"peerDependenciesMeta": {
|
|
33
|
+
"typescript": {
|
|
34
|
+
"optional": true
|
|
35
|
+
}
|
|
36
|
+
},
|
|
29
37
|
"files": [
|
|
30
38
|
"dist",
|
|
31
39
|
"src",
|
|
@@ -36,6 +44,9 @@
|
|
|
36
44
|
"./contract-builder": "./dist/contract-builder.mjs",
|
|
37
45
|
"./package.json": "./package.json"
|
|
38
46
|
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=24"
|
|
49
|
+
},
|
|
39
50
|
"repository": {
|
|
40
51
|
"type": "git",
|
|
41
52
|
"url": "https://github.com/prisma/prisma-next.git",
|
package/src/build-contract.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
computeStorageHash,
|
|
5
5
|
} from '@prisma-next/contract/hashing';
|
|
6
6
|
import {
|
|
7
|
+
asNamespaceId,
|
|
7
8
|
type ColumnDefault,
|
|
8
9
|
type ColumnDefaultLiteralInputValue,
|
|
9
10
|
type Contract,
|
|
@@ -11,13 +12,17 @@ import {
|
|
|
11
12
|
type ContractModel,
|
|
12
13
|
type ContractRelation,
|
|
13
14
|
type ContractValueObject,
|
|
15
|
+
type CrossReference,
|
|
14
16
|
coreHash,
|
|
17
|
+
crossRef,
|
|
15
18
|
type ExecutionMutationDefault,
|
|
16
19
|
type JsonValue,
|
|
17
20
|
type StorageHashBase,
|
|
18
21
|
} from '@prisma-next/contract/types';
|
|
22
|
+
import { type CapabilityMatrix, mergeCapabilityMatrices } from '@prisma-next/contract-authoring';
|
|
19
23
|
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
20
|
-
import {
|
|
24
|
+
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
25
|
+
import { sqlContractCanonicalizationHooks } from '@prisma-next/sql-contract/canonicalization-hooks';
|
|
21
26
|
import { validateIndexTypes } from '@prisma-next/sql-contract/index-type-validation';
|
|
22
27
|
import {
|
|
23
28
|
createIndexTypeRegistry,
|
|
@@ -26,6 +31,7 @@ import {
|
|
|
26
31
|
} from '@prisma-next/sql-contract/index-types';
|
|
27
32
|
import {
|
|
28
33
|
applyFkDefaults,
|
|
34
|
+
buildSqlNamespace,
|
|
29
35
|
isPostgresEnumStorageEntry,
|
|
30
36
|
type PostgresEnumStorageEntry,
|
|
31
37
|
type SqlNamespaceTablesInput,
|
|
@@ -38,6 +44,7 @@ import {
|
|
|
38
44
|
toStorageTypeInstance,
|
|
39
45
|
} from '@prisma-next/sql-contract/types';
|
|
40
46
|
import { validateStorageSemantics } from '@prisma-next/sql-contract/validators';
|
|
47
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
41
48
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
42
49
|
import type {
|
|
43
50
|
ContractDefinition,
|
|
@@ -146,6 +153,17 @@ function isValueObjectField(
|
|
|
146
153
|
const JSONB_CODEC_ID = 'pg/jsonb@1';
|
|
147
154
|
const JSONB_NATIVE_TYPE = 'jsonb';
|
|
148
155
|
|
|
156
|
+
function resolveModelNamespaceId(
|
|
157
|
+
model: ModelNode,
|
|
158
|
+
modelNameToNamespaceId: ReadonlyMap<string, string>,
|
|
159
|
+
targetId: string,
|
|
160
|
+
): string {
|
|
161
|
+
if (model.namespaceId !== undefined && model.namespaceId.length > 0) {
|
|
162
|
+
return model.namespaceId;
|
|
163
|
+
}
|
|
164
|
+
return modelNameToNamespaceId.get(model.modelName) ?? defaultModelNamespaceId(targetId);
|
|
165
|
+
}
|
|
166
|
+
|
|
149
167
|
function buildStorageColumn(
|
|
150
168
|
field: FieldNode | ValueObjectFieldNode,
|
|
151
169
|
codecLookup?: CodecLookup,
|
|
@@ -213,7 +231,7 @@ function buildDomainField(
|
|
|
213
231
|
|
|
214
232
|
function collectStorageNamespaceCoordinateIds(definition: ContractDefinition): Set<string> {
|
|
215
233
|
const ids = new Set<string>();
|
|
216
|
-
ids.add(
|
|
234
|
+
ids.add(defaultModelNamespaceId(definition.target.targetId));
|
|
217
235
|
for (const id of definition.namespaces ?? []) {
|
|
218
236
|
if (id.length > 0) {
|
|
219
237
|
ids.add(id);
|
|
@@ -228,6 +246,11 @@ function collectStorageNamespaceCoordinateIds(definition: ContractDefinition): S
|
|
|
228
246
|
}
|
|
229
247
|
|
|
230
248
|
const POSTGRES_ENUM_NAMESPACE_ID = 'public';
|
|
249
|
+
const POSTGRES_DEFAULT_NAMESPACE_ID = 'public';
|
|
250
|
+
|
|
251
|
+
function defaultModelNamespaceId(targetId: string): string {
|
|
252
|
+
return targetId === 'postgres' ? POSTGRES_DEFAULT_NAMESPACE_ID : UNBOUND_NAMESPACE_ID;
|
|
253
|
+
}
|
|
231
254
|
|
|
232
255
|
function partitionStorageTypesForTarget(
|
|
233
256
|
targetId: string,
|
|
@@ -286,13 +309,19 @@ export function buildSqlContractFromDefinition(
|
|
|
286
309
|
|
|
287
310
|
const tablesByNamespace: Record<string, Record<string, StorageTable>> = {};
|
|
288
311
|
const tableNameToNamespaceId = new Map<string, string>();
|
|
312
|
+
const modelNameToNamespaceId = new Map<string, string>();
|
|
289
313
|
const executionDefaults: ExecutionMutationDefault[] = [];
|
|
290
|
-
const
|
|
291
|
-
const roots: Record<string,
|
|
314
|
+
const modelsByNamespace: Record<string, Record<string, ContractModel>> = {};
|
|
315
|
+
const roots: Record<string, CrossReference> = {};
|
|
292
316
|
|
|
293
317
|
for (const semanticModel of definition.models) {
|
|
294
318
|
const tableName = semanticModel.tableName;
|
|
295
|
-
|
|
319
|
+
const namespaceId =
|
|
320
|
+
semanticModel.namespaceId !== undefined && semanticModel.namespaceId.length > 0
|
|
321
|
+
? semanticModel.namespaceId
|
|
322
|
+
: defaultModelNamespaceId(target);
|
|
323
|
+
modelNameToNamespaceId.set(semanticModel.modelName, namespaceId);
|
|
324
|
+
roots[tableName] = crossRef(semanticModel.modelName, namespaceId);
|
|
296
325
|
|
|
297
326
|
// --- Build storage table ---
|
|
298
327
|
|
|
@@ -344,11 +373,6 @@ export function buildSqlContractFromDefinition(
|
|
|
344
373
|
}
|
|
345
374
|
}
|
|
346
375
|
|
|
347
|
-
const namespaceId =
|
|
348
|
-
semanticModel.namespaceId !== undefined && semanticModel.namespaceId.length > 0
|
|
349
|
-
? semanticModel.namespaceId
|
|
350
|
-
: UNBOUND_NAMESPACE_ID;
|
|
351
|
-
|
|
352
376
|
const foreignKeys = (semanticModel.foreignKeys ?? []).map((fk) => {
|
|
353
377
|
const targetModel = assertKnownTargetModel(
|
|
354
378
|
modelsByName,
|
|
@@ -366,11 +390,11 @@ export function buildSqlContractFromDefinition(
|
|
|
366
390
|
fk.references.namespaceId ??
|
|
367
391
|
(targetModel.namespaceId !== undefined && targetModel.namespaceId.length > 0
|
|
368
392
|
? targetModel.namespaceId
|
|
369
|
-
:
|
|
393
|
+
: defaultModelNamespaceId(target));
|
|
370
394
|
return {
|
|
371
|
-
source: { namespaceId, tableName, columns: fk.columns },
|
|
395
|
+
source: { namespaceId: asNamespaceId(namespaceId), tableName, columns: fk.columns },
|
|
372
396
|
target: {
|
|
373
|
-
namespaceId: targetNamespaceId,
|
|
397
|
+
namespaceId: asNamespaceId(targetNamespaceId),
|
|
374
398
|
tableName: fk.references.table,
|
|
375
399
|
columns: fk.references.columns,
|
|
376
400
|
},
|
|
@@ -461,7 +485,10 @@ export function buildSqlContractFromDefinition(
|
|
|
461
485
|
);
|
|
462
486
|
|
|
463
487
|
modelRelations[relation.fieldName] = {
|
|
464
|
-
to:
|
|
488
|
+
to: crossRef(
|
|
489
|
+
relation.toModel,
|
|
490
|
+
resolveModelNamespaceId(targetModel, modelNameToNamespaceId, target),
|
|
491
|
+
),
|
|
465
492
|
// RelationDefinition.cardinality includes 'N:M' which isn't in
|
|
466
493
|
// ContractReferenceRelation yet — cast is needed until the contract
|
|
467
494
|
// type is extended to cover many-to-many.
|
|
@@ -482,7 +509,12 @@ export function buildSqlContractFromDefinition(
|
|
|
482
509
|
};
|
|
483
510
|
}
|
|
484
511
|
|
|
485
|
-
|
|
512
|
+
let namespaceModels = modelsByNamespace[namespaceId];
|
|
513
|
+
if (namespaceModels === undefined) {
|
|
514
|
+
namespaceModels = {};
|
|
515
|
+
modelsByNamespace[namespaceId] = namespaceModels;
|
|
516
|
+
}
|
|
517
|
+
namespaceModels[semanticModel.modelName] = {
|
|
486
518
|
storage: {
|
|
487
519
|
table: tableName,
|
|
488
520
|
fields: storageFields,
|
|
@@ -526,19 +558,24 @@ export function buildSqlContractFromDefinition(
|
|
|
526
558
|
namespaceCoordinateIds.add(id);
|
|
527
559
|
}
|
|
528
560
|
const { createNamespace } = definition;
|
|
529
|
-
const namespaces
|
|
530
|
-
[
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
561
|
+
const namespaces = blindCast<
|
|
562
|
+
SqlStorageInput['namespaces'],
|
|
563
|
+
'contract authoring materialises each namespace coordinate from the model set and explicit namespace list'
|
|
564
|
+
>(
|
|
565
|
+
Object.fromEntries(
|
|
566
|
+
[...namespaceCoordinateIds].sort().map((id) => {
|
|
567
|
+
const enumTypes = namespaceEnumTypesById[id];
|
|
568
|
+
const nsInput: SqlNamespaceTablesInput = {
|
|
569
|
+
id,
|
|
570
|
+
tables: tablesByNamespace[id] ?? {},
|
|
571
|
+
...ifDefined('enum', enumTypes),
|
|
572
|
+
};
|
|
573
|
+
return [id, createNamespace ? createNamespace(nsInput) : buildSqlNamespace(nsInput)];
|
|
574
|
+
}),
|
|
575
|
+
),
|
|
539
576
|
);
|
|
540
577
|
const storageWithoutHash = {
|
|
541
|
-
types: documentTypes,
|
|
578
|
+
...(Object.keys(documentTypes).length > 0 ? { types: documentTypes } : {}),
|
|
542
579
|
namespaces,
|
|
543
580
|
};
|
|
544
581
|
const storageHash: StorageHashBase<string> = definition.storageHash
|
|
@@ -547,8 +584,9 @@ export function buildSqlContractFromDefinition(
|
|
|
547
584
|
target,
|
|
548
585
|
targetFamily,
|
|
549
586
|
storage: storageWithoutHash as Record<string, unknown>,
|
|
587
|
+
...sqlContractCanonicalizationHooks,
|
|
550
588
|
});
|
|
551
|
-
const storage = new SqlStorage({ ...storageWithoutHash, storageHash }
|
|
589
|
+
const storage = new SqlStorage({ ...storageWithoutHash, storageHash });
|
|
552
590
|
|
|
553
591
|
const executionSection =
|
|
554
592
|
executionDefaults.length > 0
|
|
@@ -578,8 +616,24 @@ export function buildSqlContractFromDefinition(
|
|
|
578
616
|
}
|
|
579
617
|
}
|
|
580
618
|
|
|
581
|
-
const
|
|
582
|
-
|
|
619
|
+
const extensionPackCapabilitySources = definition.extensionPacks
|
|
620
|
+
? Object.values(definition.extensionPacks).map(
|
|
621
|
+
(pack) => pack.capabilities as CapabilityMatrix | undefined,
|
|
622
|
+
)
|
|
623
|
+
: [];
|
|
624
|
+
const capabilities = mergeCapabilityMatrices(
|
|
625
|
+
definition.target.capabilities as CapabilityMatrix | undefined,
|
|
626
|
+
...extensionPackCapabilitySources,
|
|
627
|
+
);
|
|
628
|
+
// Internal `profileHash` computation is unchanged from `origin/main`: it
|
|
629
|
+
// continues to fingerprint the author-declared capability subset. With
|
|
630
|
+
// `capabilities` removed from the `defineContract` input that subset is
|
|
631
|
+
// now always empty, so the hash naturally stabilises at `hash({})`.
|
|
632
|
+
const profileHash = computeProfileHash({
|
|
633
|
+
target,
|
|
634
|
+
targetFamily,
|
|
635
|
+
capabilities: {},
|
|
636
|
+
});
|
|
583
637
|
|
|
584
638
|
const executionWithHash = executionSection
|
|
585
639
|
? {
|
|
@@ -618,14 +672,32 @@ export function buildSqlContractFromDefinition(
|
|
|
618
672
|
)
|
|
619
673
|
: undefined;
|
|
620
674
|
|
|
675
|
+
const defaultNamespaceId = defaultModelNamespaceId(target);
|
|
676
|
+
const domainNamespaceIds = new Set(Object.keys(modelsByNamespace));
|
|
677
|
+
if (domainNamespaceIds.size === 0) {
|
|
678
|
+
domainNamespaceIds.add(defaultNamespaceId);
|
|
679
|
+
}
|
|
680
|
+
if (valueObjects !== undefined) {
|
|
681
|
+
domainNamespaceIds.add(defaultNamespaceId);
|
|
682
|
+
}
|
|
683
|
+
const domainNamespaces = Object.fromEntries(
|
|
684
|
+
[...domainNamespaceIds].sort().map((namespaceId) => {
|
|
685
|
+
const modelsInNs = modelsByNamespace[namespaceId] ?? {};
|
|
686
|
+
const namespaceSlice =
|
|
687
|
+
namespaceId === defaultNamespaceId && valueObjects !== undefined
|
|
688
|
+
? { models: modelsInNs, valueObjects }
|
|
689
|
+
: { models: modelsInNs };
|
|
690
|
+
return [namespaceId, namespaceSlice];
|
|
691
|
+
}),
|
|
692
|
+
);
|
|
693
|
+
|
|
621
694
|
const contract: Contract<SqlStorage> = {
|
|
622
695
|
target,
|
|
623
696
|
targetFamily,
|
|
624
|
-
|
|
697
|
+
domain: { namespaces: domainNamespaces },
|
|
625
698
|
roots,
|
|
626
699
|
storage,
|
|
627
700
|
...(executionWithHash ? { execution: executionWithHash } : {}),
|
|
628
|
-
...ifDefined('valueObjects', valueObjects),
|
|
629
701
|
extensionPacks,
|
|
630
702
|
capabilities,
|
|
631
703
|
profileHash,
|
package/src/config-types.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { pathToFileURL } from 'node:url';
|
|
2
2
|
import type { ContractConfig } from '@prisma-next/config/config-types';
|
|
3
3
|
import type { Contract } from '@prisma-next/contract/types';
|
|
4
|
+
import type { TargetPackRef } from '@prisma-next/framework-components/components';
|
|
4
5
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
5
6
|
import { ok } from '@prisma-next/utils/result';
|
|
6
7
|
import { extname } from 'pathe';
|
|
8
|
+
import { buildSqlContractFromDefinition } from './build-contract';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Derives the emit output path from the TS contract input so artefacts land
|
|
@@ -17,6 +19,18 @@ function defaultOutputFromContractPath(contractPath: string): string {
|
|
|
17
19
|
return `${contractPath.slice(0, -ext.length)}.json`;
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
export function emptyContract(options: {
|
|
23
|
+
readonly output?: string;
|
|
24
|
+
readonly target: TargetPackRef<'sql', string>;
|
|
25
|
+
}): ContractConfig {
|
|
26
|
+
return {
|
|
27
|
+
source: {
|
|
28
|
+
load: async () => ok(buildSqlContractFromDefinition({ target: options.target, models: [] })),
|
|
29
|
+
},
|
|
30
|
+
...ifDefined('output', options.output),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
20
34
|
export function typescriptContract(contract: Contract, output?: string): ContractConfig {
|
|
21
35
|
return {
|
|
22
36
|
source: {
|
package/src/contract-builder.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
SqlNamespaceTablesInput,
|
|
12
12
|
StorageTypeInstance,
|
|
13
13
|
} from '@prisma-next/sql-contract/types';
|
|
14
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
14
15
|
import { buildSqlContractFromDefinition } from './build-contract';
|
|
15
16
|
import {
|
|
16
17
|
type ComposedAuthoringHelpers,
|
|
@@ -53,7 +54,6 @@ type ContractDefinition<
|
|
|
53
54
|
Types extends Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
54
55
|
Models extends Record<string, ModelLike>,
|
|
55
56
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
56
|
-
Capabilities extends Record<string, Record<string, boolean>> | undefined,
|
|
57
57
|
Naming extends ContractInput['naming'] | undefined,
|
|
58
58
|
StorageHash extends string | undefined,
|
|
59
59
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
@@ -65,7 +65,6 @@ type ContractDefinition<
|
|
|
65
65
|
readonly naming?: Naming;
|
|
66
66
|
readonly storageHash?: StorageHash;
|
|
67
67
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
68
|
-
readonly capabilities?: Capabilities;
|
|
69
68
|
readonly namespaces?: Namespaces;
|
|
70
69
|
readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
|
|
71
70
|
readonly types?: Types;
|
|
@@ -77,7 +76,6 @@ type ContractScaffold<
|
|
|
77
76
|
Family extends FamilyPackRef<string>,
|
|
78
77
|
Target extends TargetPackRef<'sql', string>,
|
|
79
78
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
80
|
-
Capabilities extends Record<string, Record<string, boolean>> | undefined,
|
|
81
79
|
Naming extends ContractInput['naming'] | undefined,
|
|
82
80
|
StorageHash extends string | undefined,
|
|
83
81
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
@@ -89,9 +87,10 @@ type ContractScaffold<
|
|
|
89
87
|
readonly naming?: Naming;
|
|
90
88
|
readonly storageHash?: StorageHash;
|
|
91
89
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
92
|
-
readonly capabilities?: Capabilities;
|
|
93
90
|
readonly namespaces?: Namespaces;
|
|
94
91
|
readonly createNamespace?: (input: SqlNamespaceTablesInput) => Namespace;
|
|
92
|
+
readonly types?: never;
|
|
93
|
+
readonly models?: never;
|
|
95
94
|
readonly codecLookup?: CodecLookup;
|
|
96
95
|
};
|
|
97
96
|
|
|
@@ -274,11 +273,7 @@ function validateExtensionPackRefs(
|
|
|
274
273
|
|
|
275
274
|
function buildContractFromDsl<Definition extends ContractInput>(
|
|
276
275
|
definition: Definition,
|
|
277
|
-
): SqlContractResult<Definition
|
|
278
|
-
|
|
279
|
-
function buildContractFromDsl(
|
|
280
|
-
definition: ContractInput,
|
|
281
|
-
): ReturnType<typeof buildSqlContractFromDefinition> {
|
|
276
|
+
): SqlContractResult<Definition> {
|
|
282
277
|
validateTargetPackRef(definition.family, definition.target);
|
|
283
278
|
validateExtensionPackRefs(definition.target, definition.extensionPacks);
|
|
284
279
|
validateNamespaceDeclarations(definition.target, definition.namespaces);
|
|
@@ -288,10 +283,10 @@ function buildContractFromDsl(
|
|
|
288
283
|
(definition.models ?? {}) as Record<string, ModelLike>,
|
|
289
284
|
);
|
|
290
285
|
|
|
291
|
-
return
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
);
|
|
286
|
+
return blindCast<
|
|
287
|
+
SqlContractResult<Definition>,
|
|
288
|
+
'buildSqlContractFromDefinition return type is wide; SqlContractResult conditional resolves correctly at runtime for any concrete Definition'
|
|
289
|
+
>(buildSqlContractFromDefinition(buildContractDefinition(definition), definition.codecLookup));
|
|
295
290
|
}
|
|
296
291
|
|
|
297
292
|
export function defineContract<
|
|
@@ -305,7 +300,6 @@ export function defineContract<
|
|
|
305
300
|
const ExtensionPacks extends
|
|
306
301
|
| Record<string, ExtensionPackRef<'sql', string>>
|
|
307
302
|
| undefined = undefined,
|
|
308
|
-
const Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
309
303
|
const Naming extends ContractInput['naming'] | undefined = undefined,
|
|
310
304
|
const StorageHash extends string | undefined = undefined,
|
|
311
305
|
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
@@ -317,7 +311,6 @@ export function defineContract<
|
|
|
317
311
|
Types,
|
|
318
312
|
Models,
|
|
319
313
|
ExtensionPacks,
|
|
320
|
-
Capabilities,
|
|
321
314
|
Naming,
|
|
322
315
|
StorageHash,
|
|
323
316
|
ForeignKeyDefaults,
|
|
@@ -330,7 +323,6 @@ export function defineContract<
|
|
|
330
323
|
Types,
|
|
331
324
|
Models,
|
|
332
325
|
ExtensionPacks,
|
|
333
|
-
Capabilities,
|
|
334
326
|
Naming,
|
|
335
327
|
StorageHash,
|
|
336
328
|
ForeignKeyDefaults,
|
|
@@ -348,7 +340,6 @@ export function defineContract<
|
|
|
348
340
|
const ExtensionPacks extends
|
|
349
341
|
| Record<string, ExtensionPackRef<'sql', string>>
|
|
350
342
|
| undefined = undefined,
|
|
351
|
-
const Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
352
343
|
const Naming extends ContractInput['naming'] | undefined = undefined,
|
|
353
344
|
const StorageHash extends string | undefined = undefined,
|
|
354
345
|
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
@@ -358,7 +349,6 @@ export function defineContract<
|
|
|
358
349
|
Family,
|
|
359
350
|
Target,
|
|
360
351
|
ExtensionPacks,
|
|
361
|
-
Capabilities,
|
|
362
352
|
Naming,
|
|
363
353
|
StorageHash,
|
|
364
354
|
ForeignKeyDefaults,
|
|
@@ -372,7 +362,6 @@ export function defineContract<
|
|
|
372
362
|
Types,
|
|
373
363
|
Models,
|
|
374
364
|
ExtensionPacks,
|
|
375
|
-
Capabilities,
|
|
376
365
|
Naming,
|
|
377
366
|
StorageHash,
|
|
378
367
|
ForeignKeyDefaults,
|
|
@@ -118,7 +118,6 @@ export interface ModelNode {
|
|
|
118
118
|
export interface ContractDefinition {
|
|
119
119
|
readonly target: TargetPackRef<'sql', string>;
|
|
120
120
|
readonly extensionPacks?: Record<string, ExtensionPackRef<'sql', string>>;
|
|
121
|
-
readonly capabilities?: Record<string, Record<string, boolean>>;
|
|
122
121
|
readonly storageHash?: string;
|
|
123
122
|
readonly foreignKeyDefaults?: ForeignKeyDefaultsState;
|
|
124
123
|
readonly storageTypes?: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>;
|
package/src/contract-dsl.ts
CHANGED
|
@@ -1209,7 +1209,6 @@ export type ContractInput<
|
|
|
1209
1209
|
>
|
|
1210
1210
|
> = Record<never, never>,
|
|
1211
1211
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined = undefined,
|
|
1212
|
-
Capabilities extends Record<string, Record<string, boolean>> | undefined = undefined,
|
|
1213
1212
|
> = {
|
|
1214
1213
|
readonly family: Family;
|
|
1215
1214
|
readonly target: Target;
|
|
@@ -1217,7 +1216,6 @@ export type ContractInput<
|
|
|
1217
1216
|
readonly naming?: NamingConfig;
|
|
1218
1217
|
readonly storageHash?: string;
|
|
1219
1218
|
readonly foreignKeyDefaults?: ForeignKeyDefaultsState;
|
|
1220
|
-
readonly capabilities?: Capabilities;
|
|
1221
1219
|
/**
|
|
1222
1220
|
* Declared namespace coordinates the contract recognises. Per-model
|
|
1223
1221
|
* `namespace` references must reference an entry in this list (or the
|
package/src/contract-lowering.ts
CHANGED
|
@@ -708,7 +708,6 @@ export function buildContractDefinition(definition: ContractInput): ContractDefi
|
|
|
708
708
|
return {
|
|
709
709
|
target: definition.target,
|
|
710
710
|
...(definition.extensionPacks ? { extensionPacks: definition.extensionPacks } : {}),
|
|
711
|
-
...(definition.capabilities ? { capabilities: definition.capabilities } : {}),
|
|
712
711
|
...(definition.storageHash ? { storageHash: definition.storageHash } : {}),
|
|
713
712
|
...(definition.foreignKeyDefaults ? { foreignKeyDefaults: definition.foreignKeyDefaults } : {}),
|
|
714
713
|
...(Object.keys(collection.storageTypes).length > 0
|
package/src/contract-types.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
ColumnDefault,
|
|
3
3
|
Contract,
|
|
4
4
|
ContractRelation,
|
|
5
|
+
NamespaceId,
|
|
5
6
|
StorageHashBase,
|
|
6
7
|
} from '@prisma-next/contract/types';
|
|
7
8
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
@@ -69,11 +70,35 @@ type DefinitionExtensionPacks<Definition> = Definition extends {
|
|
|
69
70
|
? Packs
|
|
70
71
|
: Record<never, never>;
|
|
71
72
|
|
|
72
|
-
type
|
|
73
|
-
readonly capabilities?: infer
|
|
73
|
+
type ExtractPackCapabilities<P> = P extends {
|
|
74
|
+
readonly capabilities?: infer Caps extends Record<string, Record<string, boolean>>;
|
|
74
75
|
}
|
|
75
|
-
?
|
|
76
|
-
:
|
|
76
|
+
? Caps
|
|
77
|
+
: never;
|
|
78
|
+
|
|
79
|
+
type MergeExtensionPackCapabilities<Packs> =
|
|
80
|
+
Packs extends Record<string, unknown>
|
|
81
|
+
? keyof Packs extends never
|
|
82
|
+
? Record<string, never>
|
|
83
|
+
: UnionToIntersection<
|
|
84
|
+
{
|
|
85
|
+
[K in keyof Packs]: ExtractPackCapabilities<Packs[K]>;
|
|
86
|
+
}[keyof Packs]
|
|
87
|
+
>
|
|
88
|
+
: Record<string, never>;
|
|
89
|
+
|
|
90
|
+
type Defaulted<T, Fallback> = [T] extends [never] ? Fallback : T;
|
|
91
|
+
|
|
92
|
+
// Build-time capability derivation no longer reads an author-declared
|
|
93
|
+
// `capabilities` block — that field was removed from the `defineContract`
|
|
94
|
+
// input. The build-time matrix is the merge of the target pack's caps and
|
|
95
|
+
// every extension pack's caps; adapter and driver caps are layered in by
|
|
96
|
+
// `enrichContract` at CLI emit time.
|
|
97
|
+
type DerivedCapabilities<Definition> = Defaulted<
|
|
98
|
+
ExtractPackCapabilities<DefinitionTarget<Definition>>,
|
|
99
|
+
Record<string, never>
|
|
100
|
+
> &
|
|
101
|
+
MergeExtensionPackCapabilities<DefinitionExtensionPacks<Definition>>;
|
|
77
102
|
|
|
78
103
|
type DefinitionTargetId<Definition> = Definition extends {
|
|
79
104
|
readonly target: TargetPackRef<'sql', infer Target>;
|
|
@@ -509,12 +534,12 @@ type BuiltStorageTables<Definition> = {
|
|
|
509
534
|
readonly indexes: ReadonlyArray<Index>;
|
|
510
535
|
readonly foreignKeys: ReadonlyArray<{
|
|
511
536
|
readonly source: {
|
|
512
|
-
readonly namespaceId:
|
|
537
|
+
readonly namespaceId: NamespaceId;
|
|
513
538
|
readonly tableName: string;
|
|
514
539
|
readonly columns: readonly string[];
|
|
515
540
|
};
|
|
516
541
|
readonly target: {
|
|
517
|
-
readonly namespaceId:
|
|
542
|
+
readonly namespaceId: NamespaceId;
|
|
518
543
|
readonly tableName: string;
|
|
519
544
|
readonly columns: readonly string[];
|
|
520
545
|
};
|
|
@@ -538,33 +563,48 @@ type BuiltStorageTables<Definition> = {
|
|
|
538
563
|
: Record<string, never>);
|
|
539
564
|
};
|
|
540
565
|
|
|
541
|
-
type
|
|
566
|
+
type BuiltDocumentScopedTypes<Definition> = {
|
|
542
567
|
readonly [K in keyof DefinitionTypes<Definition> as DefinitionTypes<Definition>[K] extends PostgresEnumStorageEntry
|
|
543
568
|
? never
|
|
544
569
|
: K]: DefinitionTypes<Definition>[K];
|
|
545
570
|
};
|
|
546
571
|
|
|
572
|
+
type BuiltDomain<Definition> =
|
|
573
|
+
BuiltDocumentScopedTypes<Definition> extends Record<never, never>
|
|
574
|
+
? Record<string, never>
|
|
575
|
+
: {
|
|
576
|
+
readonly __unbound__: {
|
|
577
|
+
readonly types: BuiltDocumentScopedTypes<Definition>;
|
|
578
|
+
};
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
type DefaultStorageNamespaceId<Definition> =
|
|
582
|
+
DefinitionTargetId<Definition> extends 'postgres' ? 'public' : '__unbound__';
|
|
583
|
+
|
|
547
584
|
type BuiltStorage<Definition> = {
|
|
548
585
|
readonly storageHash: StorageHashBase<string>;
|
|
549
|
-
readonly types
|
|
550
|
-
//
|
|
551
|
-
//
|
|
552
|
-
//
|
|
553
|
-
// access without an optional-narrowing dance. The shape is
|
|
554
|
-
// inline (rather than intersecting with `SqlStorage['namespaces']`)
|
|
555
|
-
// its `Readonly<Record<string, Namespace>>` index signature doesn't
|
|
586
|
+
readonly types?: BuiltDocumentScopedTypes<Definition>;
|
|
587
|
+
// The primary namespace key is target-specific: Postgres uses `public` (the
|
|
588
|
+
// default schema), all other SQL targets use `__unbound__`. The namespace
|
|
589
|
+
// carries the narrowed tables shape so downstream DSL surfaces keep
|
|
590
|
+
// literal-keyed access without an optional-narrowing dance. The shape is
|
|
591
|
+
// described inline (rather than intersecting with `SqlStorage['namespaces']`)
|
|
592
|
+
// so its `Readonly<Record<string, Namespace>>` index signature doesn't
|
|
556
593
|
// collapse `keyof tables` to `string`. The literal object is still
|
|
557
|
-
// structurally assignable to `SqlStorage['namespaces']` because every
|
|
558
|
-
//
|
|
594
|
+
// structurally assignable to `SqlStorage['namespaces']` because every value
|
|
595
|
+
// satisfies the framework `Namespace` interface.
|
|
559
596
|
readonly namespaces: {
|
|
560
|
-
readonly
|
|
561
|
-
readonly id:
|
|
597
|
+
readonly [K in DefaultStorageNamespaceId<Definition>]: {
|
|
598
|
+
readonly id: K;
|
|
562
599
|
readonly kind: string;
|
|
563
600
|
readonly tables: BuiltStorageTables<Definition>;
|
|
564
601
|
readonly enum?: Readonly<Record<string, PostgresEnumStorageEntry>>;
|
|
565
602
|
};
|
|
566
603
|
} & {
|
|
567
|
-
readonly [Ns in Exclude<
|
|
604
|
+
readonly [Ns in Exclude<
|
|
605
|
+
DefinitionNamespaces<Definition>,
|
|
606
|
+
DefaultStorageNamespaceId<Definition>
|
|
607
|
+
>]: {
|
|
568
608
|
readonly id: Ns;
|
|
569
609
|
readonly kind: string;
|
|
570
610
|
readonly tables: Record<never, never>;
|
|
@@ -604,16 +644,11 @@ export type SqlContractResult<Definition> = ContractWithTypeMaps<
|
|
|
604
644
|
Contract<BuiltStorage<Definition>, BuiltModels<Definition>> & {
|
|
605
645
|
readonly target: DefinitionTargetId<Definition>;
|
|
606
646
|
readonly targetFamily: 'sql';
|
|
607
|
-
} & {
|
|
647
|
+
} & { readonly domain: BuiltDomain<Definition> } & {
|
|
608
648
|
readonly extensionPacks: keyof DefinitionExtensionPacks<Definition> extends never
|
|
609
649
|
? Record<string, never>
|
|
610
650
|
: DefinitionExtensionPacks<Definition>;
|
|
611
|
-
readonly capabilities:
|
|
612
|
-
string,
|
|
613
|
-
Record<string, boolean>
|
|
614
|
-
>
|
|
615
|
-
? DefinitionCapabilities<Definition>
|
|
616
|
-
: Record<string, Record<string, boolean>>;
|
|
651
|
+
readonly capabilities: DerivedCapabilities<Definition>;
|
|
617
652
|
},
|
|
618
653
|
TypeMaps<
|
|
619
654
|
CodecTypesFromDefinition<Definition>,
|