@prisma-next/sql-contract-ts 0.14.0-dev.5 → 0.14.0-dev.50
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-CQ4u83jx.mjs → build-contract-Bi8UaU_S.mjs} +28 -28
- package/dist/build-contract-Bi8UaU_S.mjs.map +1 -0
- package/dist/config-types.d.mts +2 -0
- package/dist/config-types.d.mts.map +1 -1
- package/dist/config-types.mjs +2 -1
- package/dist/config-types.mjs.map +1 -1
- package/dist/contract-builder.d.mts +42 -173
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +16 -74
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +10 -10
- package/src/authoring-helper-runtime.ts +2 -6
- package/src/build-contract.ts +62 -47
- package/src/composed-authoring-helpers.ts +3 -6
- package/src/config-types.ts +7 -1
- package/src/contract-builder.ts +8 -5
- package/src/contract-definition.ts +4 -4
- package/src/contract-dsl.ts +108 -41
- package/src/contract-lowering.ts +2 -1
- package/src/contract-types.ts +34 -10
- package/src/enum-type.ts +14 -306
- package/dist/build-contract-CQ4u83jx.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.14.0-dev.
|
|
3
|
+
"version": "0.14.0-dev.50",
|
|
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.14.0-dev.
|
|
10
|
-
"@prisma-next/contract": "0.14.0-dev.
|
|
11
|
-
"@prisma-next/contract-authoring": "0.14.0-dev.
|
|
12
|
-
"@prisma-next/framework-components": "0.14.0-dev.
|
|
13
|
-
"@prisma-next/sql-contract": "0.14.0-dev.
|
|
14
|
-
"@prisma-next/utils": "0.14.0-dev.
|
|
9
|
+
"@prisma-next/config": "0.14.0-dev.50",
|
|
10
|
+
"@prisma-next/contract": "0.14.0-dev.50",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.14.0-dev.50",
|
|
12
|
+
"@prisma-next/framework-components": "0.14.0-dev.50",
|
|
13
|
+
"@prisma-next/sql-contract": "0.14.0-dev.50",
|
|
14
|
+
"@prisma-next/utils": "0.14.0-dev.50",
|
|
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.14.0-dev.
|
|
21
|
-
"@prisma-next/tsconfig": "0.14.0-dev.
|
|
20
|
+
"@prisma-next/test-utils": "0.14.0-dev.50",
|
|
21
|
+
"@prisma-next/tsconfig": "0.14.0-dev.50",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.21.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.14.0-dev.
|
|
24
|
+
"@prisma-next/tsdown": "0.14.0-dev.50",
|
|
25
25
|
"tsdown": "0.22.1",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.8"
|
|
@@ -63,7 +63,7 @@ export function createTypeHelpersFromNamespace(
|
|
|
63
63
|
continue;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
helpers[key] = createTypeHelpersFromNamespace(value
|
|
66
|
+
helpers[key] = createTypeHelpersFromNamespace(value, currentPath);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
return helpers;
|
|
@@ -133,11 +133,7 @@ export function createFieldHelpersFromNamespace(
|
|
|
133
133
|
continue;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
helpers[key] = createFieldHelpersFromNamespace(
|
|
137
|
-
value as AuthoringFieldNamespace,
|
|
138
|
-
createLeafHelper,
|
|
139
|
-
currentPath,
|
|
140
|
-
);
|
|
136
|
+
helpers[key] = createFieldHelpersFromNamespace(value, createLeafHelper, currentPath);
|
|
141
137
|
}
|
|
142
138
|
|
|
143
139
|
return helpers;
|
package/src/build-contract.ts
CHANGED
|
@@ -33,9 +33,8 @@ import {
|
|
|
33
33
|
} from '@prisma-next/sql-contract/index-types';
|
|
34
34
|
import {
|
|
35
35
|
applyFkDefaults,
|
|
36
|
-
buildSqlNamespace,
|
|
37
36
|
type CheckConstraintInput,
|
|
38
|
-
type
|
|
37
|
+
type SqlNamespaceInput,
|
|
39
38
|
SqlStorage,
|
|
40
39
|
type SqlStorageInput,
|
|
41
40
|
type StorageColumn,
|
|
@@ -74,10 +73,23 @@ function encodeColumnDefault(
|
|
|
74
73
|
defaultInput: ColumnDefault,
|
|
75
74
|
codecId: string,
|
|
76
75
|
codecLookup?: CodecLookup,
|
|
76
|
+
many = false,
|
|
77
77
|
): ColumnDefault {
|
|
78
78
|
if (defaultInput.kind === 'function') {
|
|
79
79
|
return { kind: 'function', expression: defaultInput.expression };
|
|
80
80
|
}
|
|
81
|
+
if (many) {
|
|
82
|
+
if (!Array.isArray(defaultInput.value)) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Literal default on a list column must be an array; received ${typeof defaultInput.value}. ` +
|
|
85
|
+
'A scalar default on a list field must be rejected at the authoring surface.',
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
kind: 'literal',
|
|
90
|
+
value: defaultInput.value.map((element) => encodeViaCodec(element, codecId, codecLookup)),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
81
93
|
return {
|
|
82
94
|
kind: 'literal',
|
|
83
95
|
value: encodeViaCodec(defaultInput.value, codecId, codecLookup),
|
|
@@ -235,28 +247,28 @@ function buildStorageColumn(
|
|
|
235
247
|
};
|
|
236
248
|
}
|
|
237
249
|
|
|
238
|
-
if (field.many) {
|
|
239
|
-
return {
|
|
240
|
-
nativeType: JSONB_NATIVE_TYPE,
|
|
241
|
-
codecId: JSONB_CODEC_ID,
|
|
242
|
-
nullable: field.nullable,
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
250
|
const codecId = field.descriptor.codecId;
|
|
247
251
|
const encodedDefault =
|
|
248
252
|
field.default !== undefined
|
|
249
|
-
? encodeColumnDefault(field.default, codecId, codecLookup)
|
|
253
|
+
? encodeColumnDefault(field.default, codecId, codecLookup, field.many === true)
|
|
250
254
|
: undefined;
|
|
251
255
|
|
|
256
|
+
// `storageValueSetRef` (derived from an `enumTypeHandle`) takes precedence
|
|
257
|
+
// when present — the established domain-enum path. `field.descriptor.valueSet`
|
|
258
|
+
// is the fallback: set by an entity-ref type constructor (e.g. `pg.enum(Ref)`)
|
|
259
|
+
// that resolved the field's type against a value-set-deriving entity with no
|
|
260
|
+
// domain enum involved. A field carries at most one of the two in practice.
|
|
261
|
+
const valueSet = storageValueSetRef ?? field.descriptor.valueSet;
|
|
262
|
+
|
|
252
263
|
return {
|
|
253
264
|
nativeType: field.descriptor.nativeType,
|
|
254
265
|
codecId,
|
|
255
266
|
nullable: field.nullable,
|
|
267
|
+
...(field.many ? { many: true as const } : {}),
|
|
256
268
|
...ifDefined('typeParams', field.descriptor.typeParams),
|
|
257
269
|
...ifDefined('default', encodedDefault),
|
|
258
270
|
...ifDefined('typeRef', field.descriptor.typeRef),
|
|
259
|
-
...ifDefined('valueSet',
|
|
271
|
+
...ifDefined('valueSet', valueSet),
|
|
260
272
|
};
|
|
261
273
|
}
|
|
262
274
|
|
|
@@ -308,18 +320,15 @@ function ensureUnboundNamespaceSlot(
|
|
|
308
320
|
if (Object.hasOwn(namespaces, UNBOUND_NAMESPACE_ID)) {
|
|
309
321
|
return namespaces;
|
|
310
322
|
}
|
|
311
|
-
const unboundInput:
|
|
323
|
+
const unboundInput: SqlNamespaceInput = {
|
|
312
324
|
id: UNBOUND_NAMESPACE_ID,
|
|
313
325
|
entries: { table: {} },
|
|
314
326
|
};
|
|
315
|
-
const unbound = createNamespace
|
|
316
|
-
return
|
|
317
|
-
SqlStorageInput['namespaces'],
|
|
318
|
-
'createNamespace may return a target namespace concretion; the unbound slot matches SqlNamespace at runtime'
|
|
319
|
-
>({
|
|
327
|
+
const unbound = createNamespace(unboundInput);
|
|
328
|
+
return {
|
|
320
329
|
[UNBOUND_NAMESPACE_ID]: unbound,
|
|
321
330
|
...namespaces,
|
|
322
|
-
}
|
|
331
|
+
};
|
|
323
332
|
}
|
|
324
333
|
|
|
325
334
|
export function buildSqlContractFromDefinition(
|
|
@@ -375,6 +384,7 @@ export function buildSqlContractFromDefinition(
|
|
|
375
384
|
const fieldToColumn: Record<string, string> = {};
|
|
376
385
|
const domainFields: Record<string, ContractField> = {};
|
|
377
386
|
const domainFieldRefs: Record<string, DomainFieldRef> = {};
|
|
387
|
+
const checksForTable: CheckConstraintInput[] = [];
|
|
378
388
|
|
|
379
389
|
for (const field of semanticModel.fields) {
|
|
380
390
|
const executionDefaultPhases =
|
|
@@ -421,6 +431,25 @@ export function buildSqlContractFromDefinition(
|
|
|
421
431
|
columns[field.columnName] = column;
|
|
422
432
|
fieldToColumn[field.fieldName] = field.columnName;
|
|
423
433
|
|
|
434
|
+
// A domain enum (`storageValueSetRef`, from an `enumType()` handle) is
|
|
435
|
+
// stored as a plain scalar column (`text`, `int4`, …) with no native
|
|
436
|
+
// type of its own to enforce membership, so it needs an explicit
|
|
437
|
+
// CHECK — scalar or array, since a `text[]` array has no element-level
|
|
438
|
+
// enforcement either. A value set resolved by an entity-ref type
|
|
439
|
+
// constructor (`field.descriptor.valueSet`, e.g. `pg.enum(Ref)`) binds
|
|
440
|
+
// the column to a codec/native-type pairing that IS the storage-level
|
|
441
|
+
// enforcement (a Postgres native enum type, or another target's
|
|
442
|
+
// equivalent) — including array columns, since the target enforces
|
|
443
|
+
// membership on every element of a native-typed array — so no CHECK
|
|
444
|
+
// for those.
|
|
445
|
+
if (column.valueSet !== undefined && storageValueSetRef !== undefined) {
|
|
446
|
+
checksForTable.push({
|
|
447
|
+
name: `${tableName}_${field.columnName}_check`,
|
|
448
|
+
column: field.columnName,
|
|
449
|
+
valueSet: column.valueSet,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
424
453
|
domainFields[field.fieldName] = buildDomainField(field, column, domainValueSetRef);
|
|
425
454
|
|
|
426
455
|
if (isValueObjectField(field)) {
|
|
@@ -511,15 +540,6 @@ export function buildSqlContractFromDefinition(
|
|
|
511
540
|
// materialised onto the base `ModelNode`, so the variant builds a domain
|
|
512
541
|
// model (below) but no storage table of its own.
|
|
513
542
|
if (!semanticModel.sharesBaseTable) {
|
|
514
|
-
const checksForTable: CheckConstraintInput[] = Object.entries(columns).flatMap(
|
|
515
|
-
([columnName, col]) => {
|
|
516
|
-
const valueSet = col.valueSet;
|
|
517
|
-
return valueSet === undefined
|
|
518
|
-
? []
|
|
519
|
-
: [{ name: `${tableName}_${columnName}_check`, column: columnName, valueSet }];
|
|
520
|
-
},
|
|
521
|
-
);
|
|
522
|
-
|
|
523
543
|
const tableInput: StorageTableInput = {
|
|
524
544
|
columns,
|
|
525
545
|
...ifDefined('control', semanticModel.control),
|
|
@@ -729,25 +749,20 @@ export function buildSqlContractFromDefinition(
|
|
|
729
749
|
}
|
|
730
750
|
|
|
731
751
|
const { createNamespace } = definition;
|
|
732
|
-
const namespaces =
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
},
|
|
747
|
-
};
|
|
748
|
-
return [id, createNamespace ? createNamespace(nsInput) : buildSqlNamespace(nsInput)];
|
|
749
|
-
}),
|
|
750
|
-
),
|
|
752
|
+
const namespaces: SqlStorageInput['namespaces'] = Object.fromEntries(
|
|
753
|
+
[...namespaceCoordinateIds].sort().map((id) => {
|
|
754
|
+
const valueSetEntries = storageValueSetsByNs[id];
|
|
755
|
+
const nsInput: SqlNamespaceInput = {
|
|
756
|
+
id,
|
|
757
|
+
entries: {
|
|
758
|
+
table: tablesByNamespace[id] ?? {},
|
|
759
|
+
...(valueSetEntries !== undefined && Object.keys(valueSetEntries).length > 0
|
|
760
|
+
? { valueSet: valueSetEntries }
|
|
761
|
+
: {}),
|
|
762
|
+
},
|
|
763
|
+
};
|
|
764
|
+
return [id, createNamespace(nsInput)];
|
|
765
|
+
}),
|
|
751
766
|
);
|
|
752
767
|
const storageWithoutHash = {
|
|
753
768
|
...(Object.keys(documentTypes).length > 0 ? { types: documentTypes } : {}),
|
|
@@ -13,9 +13,6 @@ import type {
|
|
|
13
13
|
} from '@prisma-next/framework-components/authoring';
|
|
14
14
|
import {
|
|
15
15
|
assertNoCrossRegistryCollisions,
|
|
16
|
-
isAuthoringEntityTypeDescriptor,
|
|
17
|
-
isAuthoringFieldPresetDescriptor,
|
|
18
|
-
isAuthoringTypeConstructorDescriptor,
|
|
19
16
|
mergeAuthoringNamespaces,
|
|
20
17
|
} from '@prisma-next/framework-components/authoring';
|
|
21
18
|
import type {
|
|
@@ -183,7 +180,7 @@ function composeTypeNamespace(components: readonly AuthoringComponent[]): Author
|
|
|
183
180
|
for (const component of components) {
|
|
184
181
|
const ns = extractTypeNamespace(component);
|
|
185
182
|
if (Object.keys(ns).length > 0) {
|
|
186
|
-
mergeAuthoringNamespaces(merged, ns, [],
|
|
183
|
+
mergeAuthoringNamespaces(merged, ns, [], 'typeConstructor', 'type');
|
|
187
184
|
}
|
|
188
185
|
}
|
|
189
186
|
return merged as AuthoringTypeNamespace;
|
|
@@ -194,7 +191,7 @@ function composeFieldNamespace(components: readonly AuthoringComponent[]): Autho
|
|
|
194
191
|
for (const component of components) {
|
|
195
192
|
const ns = extractFieldNamespace(component);
|
|
196
193
|
if (Object.keys(ns).length > 0) {
|
|
197
|
-
mergeAuthoringNamespaces(merged, ns, [],
|
|
194
|
+
mergeAuthoringNamespaces(merged, ns, [], 'fieldPreset', 'field');
|
|
198
195
|
}
|
|
199
196
|
}
|
|
200
197
|
return merged as AuthoringFieldNamespace;
|
|
@@ -207,7 +204,7 @@ function composeEntityNamespace(
|
|
|
207
204
|
for (const component of components) {
|
|
208
205
|
const ns = extractEntitiesNamespace(component);
|
|
209
206
|
if (Object.keys(ns).length > 0) {
|
|
210
|
-
mergeAuthoringNamespaces(merged, ns, [],
|
|
207
|
+
mergeAuthoringNamespaces(merged, ns, [], 'entity', 'entity');
|
|
211
208
|
}
|
|
212
209
|
}
|
|
213
210
|
return merged as AuthoringEntityTypeNamespace;
|
package/src/config-types.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { ContractConfig } from '@prisma-next/config/config-types';
|
|
|
3
3
|
import { applySpecifierDefaultControlPolicy } from '@prisma-next/contract/apply-specifier-default-control-policy';
|
|
4
4
|
import type { Contract, ControlPolicy } from '@prisma-next/contract/types';
|
|
5
5
|
import type { TargetPackRef } from '@prisma-next/framework-components/components';
|
|
6
|
+
import type { SqlNamespaceBase, SqlNamespaceInput } from '@prisma-next/sql-contract/types';
|
|
6
7
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
7
8
|
import { ok } from '@prisma-next/utils/result';
|
|
8
9
|
import { extname } from 'pathe';
|
|
@@ -27,13 +28,18 @@ export interface TypeScriptContractSpecifierOptions {
|
|
|
27
28
|
export function emptyContract(options: {
|
|
28
29
|
readonly output?: string;
|
|
29
30
|
readonly target: TargetPackRef<'sql', string>;
|
|
31
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
30
32
|
readonly defaultControlPolicy?: ControlPolicy;
|
|
31
33
|
}): ContractConfig {
|
|
32
34
|
return {
|
|
33
35
|
source: {
|
|
34
36
|
sourceFormat: 'typescript',
|
|
35
37
|
load: async () => {
|
|
36
|
-
const built = buildSqlContractFromDefinition({
|
|
38
|
+
const built = buildSqlContractFromDefinition({
|
|
39
|
+
target: options.target,
|
|
40
|
+
createNamespace: options.createNamespace,
|
|
41
|
+
models: [],
|
|
42
|
+
});
|
|
37
43
|
return ok(applySpecifierDefaultControlPolicy(built, options.defaultControlPolicy));
|
|
38
44
|
},
|
|
39
45
|
},
|
package/src/contract-builder.ts
CHANGED
|
@@ -6,8 +6,11 @@ import type {
|
|
|
6
6
|
FamilyPackRef,
|
|
7
7
|
TargetPackRef,
|
|
8
8
|
} from '@prisma-next/framework-components/components';
|
|
9
|
-
import type {
|
|
10
|
-
|
|
9
|
+
import type {
|
|
10
|
+
SqlNamespaceBase,
|
|
11
|
+
SqlNamespaceInput,
|
|
12
|
+
StorageTypeInstance,
|
|
13
|
+
} from '@prisma-next/sql-contract/types';
|
|
11
14
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
12
15
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
13
16
|
import { buildSqlContractFromDefinition } from './build-contract';
|
|
@@ -68,7 +71,7 @@ type ContractDefinition<
|
|
|
68
71
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
69
72
|
readonly defaultControlPolicy?: ControlPolicy;
|
|
70
73
|
readonly namespaces?: Namespaces;
|
|
71
|
-
readonly createNamespace
|
|
74
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
72
75
|
readonly types?: Types;
|
|
73
76
|
readonly models?: Models;
|
|
74
77
|
readonly codecLookup?: CodecLookup;
|
|
@@ -93,7 +96,7 @@ type ContractScaffold<
|
|
|
93
96
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
94
97
|
readonly defaultControlPolicy?: ControlPolicy;
|
|
95
98
|
readonly namespaces?: Namespaces;
|
|
96
|
-
readonly createNamespace
|
|
99
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
97
100
|
readonly types?: never;
|
|
98
101
|
readonly models?: never;
|
|
99
102
|
readonly codecLookup?: CodecLookup;
|
|
@@ -314,7 +317,7 @@ type BoundDefinitionInput<
|
|
|
314
317
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
315
318
|
readonly defaultControlPolicy?: ControlPolicy;
|
|
316
319
|
readonly namespaces?: Namespaces;
|
|
317
|
-
readonly createNamespace
|
|
320
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
318
321
|
readonly types?: Types;
|
|
319
322
|
readonly models?: Models;
|
|
320
323
|
readonly codecLookup?: CodecLookup;
|
|
@@ -6,10 +6,10 @@ import type {
|
|
|
6
6
|
import type { ForeignKeyDefaultsState } from '@prisma-next/contract-authoring';
|
|
7
7
|
import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/codec';
|
|
8
8
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
9
|
-
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
10
9
|
import type {
|
|
11
10
|
ReferentialAction,
|
|
12
|
-
|
|
11
|
+
SqlNamespaceBase,
|
|
12
|
+
SqlNamespaceInput,
|
|
13
13
|
StorageTypeInstance,
|
|
14
14
|
} from '@prisma-next/sql-contract/types';
|
|
15
15
|
import type { EnumTypeHandle } from './enum-type';
|
|
@@ -175,8 +175,8 @@ export interface ContractDefinition {
|
|
|
175
175
|
* `SqlStorage.namespaces` together with `createNamespace`.
|
|
176
176
|
*/
|
|
177
177
|
readonly namespaces?: readonly string[];
|
|
178
|
-
/** Target-supplied factory that materialises a `
|
|
179
|
-
readonly createNamespace
|
|
178
|
+
/** Target-supplied factory that materialises a `SqlNamespaceBase` concretion for a declared namespace coordinate. */
|
|
179
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
180
180
|
readonly models: readonly ModelNode[];
|
|
181
181
|
readonly valueObjects?: readonly ValueObjectNode[];
|
|
182
182
|
/**
|
package/src/contract-dsl.ts
CHANGED
|
@@ -15,8 +15,11 @@ import type {
|
|
|
15
15
|
FamilyPackRef,
|
|
16
16
|
TargetPackRef,
|
|
17
17
|
} from '@prisma-next/framework-components/components';
|
|
18
|
-
import type {
|
|
19
|
-
|
|
18
|
+
import type {
|
|
19
|
+
SqlNamespaceBase,
|
|
20
|
+
SqlNamespaceInput,
|
|
21
|
+
StorageTypeInstance,
|
|
22
|
+
} from '@prisma-next/sql-contract/types';
|
|
20
23
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
21
24
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
22
25
|
import type { NamedConstraintSpec } from './authoring-type-utils';
|
|
@@ -43,6 +46,7 @@ export type ScalarFieldState<
|
|
|
43
46
|
ColumnName extends string | undefined = string | undefined,
|
|
44
47
|
IdSpec extends NamedConstraintSpec | undefined = undefined,
|
|
45
48
|
UniqueSpec extends NamedConstraintSpec | undefined = undefined,
|
|
49
|
+
Many extends boolean = false,
|
|
46
50
|
> = {
|
|
47
51
|
readonly kind: 'scalar';
|
|
48
52
|
readonly descriptor?: (ColumnTypeDescriptor & { readonly codecId: CodecId }) | undefined;
|
|
@@ -51,6 +55,7 @@ export type ScalarFieldState<
|
|
|
51
55
|
readonly columnName?: ColumnName | undefined;
|
|
52
56
|
readonly default?: ColumnDefault | undefined;
|
|
53
57
|
readonly executionDefaults?: ExecutionMutationDefaultPhases | undefined;
|
|
58
|
+
readonly many?: Many extends true ? true : undefined;
|
|
54
59
|
} & (IdSpec extends NamedConstraintSpec ? { readonly id: IdSpec } : { readonly id?: undefined }) &
|
|
55
60
|
(UniqueSpec extends NamedConstraintSpec
|
|
56
61
|
? { readonly unique: UniqueSpec }
|
|
@@ -64,6 +69,7 @@ type AnyScalarFieldState = {
|
|
|
64
69
|
readonly columnName?: string | undefined;
|
|
65
70
|
readonly default?: ColumnDefault | undefined;
|
|
66
71
|
readonly executionDefaults?: ExecutionMutationDefaultPhases | undefined;
|
|
72
|
+
readonly many?: boolean | undefined;
|
|
67
73
|
readonly id?: NamedConstraintSpec | undefined;
|
|
68
74
|
readonly unique?: NamedConstraintSpec | undefined;
|
|
69
75
|
};
|
|
@@ -75,7 +81,8 @@ type HasNamedConstraintId<State extends AnyScalarFieldState> =
|
|
|
75
81
|
boolean,
|
|
76
82
|
string | undefined,
|
|
77
83
|
infer IdSpec,
|
|
78
|
-
NamedConstraintSpec | undefined
|
|
84
|
+
NamedConstraintSpec | undefined,
|
|
85
|
+
boolean
|
|
79
86
|
>
|
|
80
87
|
? IdSpec extends NamedConstraintSpec
|
|
81
88
|
? true
|
|
@@ -89,7 +96,8 @@ type HasNamedConstraintUnique<State extends AnyScalarFieldState> =
|
|
|
89
96
|
boolean,
|
|
90
97
|
string | undefined,
|
|
91
98
|
NamedConstraintSpec | undefined,
|
|
92
|
-
infer UniqueSpec
|
|
99
|
+
infer UniqueSpec,
|
|
100
|
+
boolean
|
|
93
101
|
>
|
|
94
102
|
? UniqueSpec extends NamedConstraintSpec
|
|
95
103
|
? true
|
|
@@ -115,7 +123,8 @@ type ApplyFieldSqlSpec<
|
|
|
115
123
|
infer Nullable,
|
|
116
124
|
infer ColumnName,
|
|
117
125
|
infer IdSpec,
|
|
118
|
-
infer UniqueSpec
|
|
126
|
+
infer UniqueSpec,
|
|
127
|
+
infer Many
|
|
119
128
|
>
|
|
120
129
|
? ScalarFieldState<
|
|
121
130
|
CodecId,
|
|
@@ -131,9 +140,10 @@ type ApplyFieldSqlSpec<
|
|
|
131
140
|
? UniqueSpec extends NamedConstraintSpec
|
|
132
141
|
? NamedConstraintSpec<UniqueName>
|
|
133
142
|
: UniqueSpec
|
|
134
|
-
: UniqueSpec
|
|
143
|
+
: UniqueSpec,
|
|
144
|
+
Many
|
|
135
145
|
>
|
|
136
|
-
:
|
|
146
|
+
: AnyScalarFieldState;
|
|
137
147
|
|
|
138
148
|
export type GeneratedFieldSpec = {
|
|
139
149
|
readonly type: ColumnTypeDescriptor;
|
|
@@ -171,10 +181,11 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
171
181
|
boolean,
|
|
172
182
|
infer ColumnName,
|
|
173
183
|
infer IdSpec,
|
|
174
|
-
infer UniqueSpec
|
|
184
|
+
infer UniqueSpec,
|
|
185
|
+
infer Many
|
|
175
186
|
>
|
|
176
|
-
? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec>
|
|
177
|
-
:
|
|
187
|
+
? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
|
|
188
|
+
: AnyScalarFieldState
|
|
178
189
|
> {
|
|
179
190
|
return new ScalarFieldBuilder({
|
|
180
191
|
...this.state,
|
|
@@ -185,10 +196,11 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
185
196
|
boolean,
|
|
186
197
|
infer ColumnName,
|
|
187
198
|
infer IdSpec,
|
|
188
|
-
infer UniqueSpec
|
|
199
|
+
infer UniqueSpec,
|
|
200
|
+
infer Many
|
|
189
201
|
>
|
|
190
|
-
? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec>
|
|
191
|
-
:
|
|
202
|
+
? ScalarFieldState<CodecId, TypeRef, true, ColumnName, IdSpec, UniqueSpec, Many>
|
|
203
|
+
: AnyScalarFieldState);
|
|
192
204
|
}
|
|
193
205
|
|
|
194
206
|
column<ColumnName extends string>(
|
|
@@ -200,10 +212,11 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
200
212
|
infer Nullable,
|
|
201
213
|
string | undefined,
|
|
202
214
|
infer IdSpec,
|
|
203
|
-
infer UniqueSpec
|
|
215
|
+
infer UniqueSpec,
|
|
216
|
+
infer Many
|
|
204
217
|
>
|
|
205
|
-
? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec>
|
|
206
|
-
:
|
|
218
|
+
? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
|
|
219
|
+
: AnyScalarFieldState
|
|
207
220
|
> {
|
|
208
221
|
return new ScalarFieldBuilder({
|
|
209
222
|
...this.state,
|
|
@@ -214,10 +227,45 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
214
227
|
infer Nullable,
|
|
215
228
|
string | undefined,
|
|
216
229
|
infer IdSpec,
|
|
217
|
-
infer UniqueSpec
|
|
230
|
+
infer UniqueSpec,
|
|
231
|
+
infer Many
|
|
218
232
|
>
|
|
219
|
-
? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec>
|
|
220
|
-
:
|
|
233
|
+
? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, Many>
|
|
234
|
+
: AnyScalarFieldState);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
many(): ScalarFieldBuilder<
|
|
238
|
+
State extends ScalarFieldState<
|
|
239
|
+
infer CodecId,
|
|
240
|
+
infer TypeRef,
|
|
241
|
+
infer Nullable,
|
|
242
|
+
infer ColumnName,
|
|
243
|
+
infer IdSpec,
|
|
244
|
+
infer UniqueSpec,
|
|
245
|
+
boolean
|
|
246
|
+
>
|
|
247
|
+
? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
|
|
248
|
+
: AnyScalarFieldState
|
|
249
|
+
> {
|
|
250
|
+
return new ScalarFieldBuilder(
|
|
251
|
+
blindCast<
|
|
252
|
+
State extends ScalarFieldState<
|
|
253
|
+
infer CodecId,
|
|
254
|
+
infer TypeRef,
|
|
255
|
+
infer Nullable,
|
|
256
|
+
infer ColumnName,
|
|
257
|
+
infer IdSpec,
|
|
258
|
+
infer UniqueSpec,
|
|
259
|
+
boolean
|
|
260
|
+
>
|
|
261
|
+
? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec, true>
|
|
262
|
+
: AnyScalarFieldState,
|
|
263
|
+
'object spread does not narrow the generic State conditional; runtime shape is correct'
|
|
264
|
+
>({
|
|
265
|
+
...this.state,
|
|
266
|
+
many: true,
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
221
269
|
}
|
|
222
270
|
|
|
223
271
|
default(value: ColumnDefaultLiteralInputValue | ColumnDefault): ScalarFieldBuilder<State> {
|
|
@@ -243,7 +291,8 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
243
291
|
infer Nullable,
|
|
244
292
|
infer ColumnName,
|
|
245
293
|
NamedConstraintSpec | undefined,
|
|
246
|
-
infer UniqueSpec
|
|
294
|
+
infer UniqueSpec,
|
|
295
|
+
infer Many
|
|
247
296
|
>
|
|
248
297
|
? ScalarFieldState<
|
|
249
298
|
CodecId,
|
|
@@ -251,9 +300,10 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
251
300
|
Nullable,
|
|
252
301
|
ColumnName,
|
|
253
302
|
NamedConstraintSpec<Name>,
|
|
254
|
-
UniqueSpec
|
|
303
|
+
UniqueSpec,
|
|
304
|
+
Many
|
|
255
305
|
>
|
|
256
|
-
:
|
|
306
|
+
: AnyScalarFieldState
|
|
257
307
|
> {
|
|
258
308
|
return new ScalarFieldBuilder({
|
|
259
309
|
...this.state,
|
|
@@ -264,7 +314,8 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
264
314
|
infer Nullable,
|
|
265
315
|
infer ColumnName,
|
|
266
316
|
NamedConstraintSpec | undefined,
|
|
267
|
-
infer UniqueSpec
|
|
317
|
+
infer UniqueSpec,
|
|
318
|
+
infer Many
|
|
268
319
|
>
|
|
269
320
|
? ScalarFieldState<
|
|
270
321
|
CodecId,
|
|
@@ -272,9 +323,10 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
272
323
|
Nullable,
|
|
273
324
|
ColumnName,
|
|
274
325
|
NamedConstraintSpec<Name>,
|
|
275
|
-
UniqueSpec
|
|
326
|
+
UniqueSpec,
|
|
327
|
+
Many
|
|
276
328
|
>
|
|
277
|
-
:
|
|
329
|
+
: AnyScalarFieldState);
|
|
278
330
|
}
|
|
279
331
|
|
|
280
332
|
unique<const Name extends string | undefined = undefined>(
|
|
@@ -286,10 +338,19 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
286
338
|
infer Nullable,
|
|
287
339
|
infer ColumnName,
|
|
288
340
|
infer IdSpec,
|
|
289
|
-
NamedConstraintSpec | undefined
|
|
341
|
+
NamedConstraintSpec | undefined,
|
|
342
|
+
infer Many
|
|
290
343
|
>
|
|
291
|
-
? ScalarFieldState<
|
|
292
|
-
|
|
344
|
+
? ScalarFieldState<
|
|
345
|
+
CodecId,
|
|
346
|
+
TypeRef,
|
|
347
|
+
Nullable,
|
|
348
|
+
ColumnName,
|
|
349
|
+
IdSpec,
|
|
350
|
+
NamedConstraintSpec<Name>,
|
|
351
|
+
Many
|
|
352
|
+
>
|
|
353
|
+
: AnyScalarFieldState
|
|
293
354
|
> {
|
|
294
355
|
return new ScalarFieldBuilder({
|
|
295
356
|
...this.state,
|
|
@@ -300,10 +361,19 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
300
361
|
infer Nullable,
|
|
301
362
|
infer ColumnName,
|
|
302
363
|
infer IdSpec,
|
|
303
|
-
NamedConstraintSpec | undefined
|
|
364
|
+
NamedConstraintSpec | undefined,
|
|
365
|
+
infer Many
|
|
304
366
|
>
|
|
305
|
-
? ScalarFieldState<
|
|
306
|
-
|
|
367
|
+
? ScalarFieldState<
|
|
368
|
+
CodecId,
|
|
369
|
+
TypeRef,
|
|
370
|
+
Nullable,
|
|
371
|
+
ColumnName,
|
|
372
|
+
IdSpec,
|
|
373
|
+
NamedConstraintSpec<Name>,
|
|
374
|
+
Many
|
|
375
|
+
>
|
|
376
|
+
: AnyScalarFieldState);
|
|
307
377
|
}
|
|
308
378
|
|
|
309
379
|
sql<const Spec extends FieldSqlSpecForState<State>>(
|
|
@@ -400,11 +470,14 @@ function namedTypeField<Handle extends EnumTypeHandle>(
|
|
|
400
470
|
function namedTypeField(typeRef: NamedStorageTypeRef): ScalarFieldBuilder {
|
|
401
471
|
if (isEnumTypeHandle(typeRef)) {
|
|
402
472
|
return new EnumScalarFieldBuilder(
|
|
403
|
-
|
|
473
|
+
blindCast<
|
|
474
|
+
ScalarFieldState<string, typeof typeRef, false, undefined>,
|
|
475
|
+
'literal object lacks explicit many; cast to the full ScalarFieldState so optional() conditional resolves Many = false'
|
|
476
|
+
>({
|
|
404
477
|
kind: 'scalar',
|
|
405
478
|
typeRef,
|
|
406
479
|
nullable: false,
|
|
407
|
-
},
|
|
480
|
+
}),
|
|
408
481
|
typeRef,
|
|
409
482
|
);
|
|
410
483
|
}
|
|
@@ -1487,7 +1560,7 @@ export type ContractInput<
|
|
|
1487
1560
|
*/
|
|
1488
1561
|
readonly namespaces?: readonly string[];
|
|
1489
1562
|
/**
|
|
1490
|
-
* Target-supplied factory that materialises a `
|
|
1563
|
+
* Target-supplied factory that materialises a `SqlNamespaceBase` concretion
|
|
1491
1564
|
* for a declared namespace coordinate. The SQL family layer is
|
|
1492
1565
|
* target-agnostic and cannot import concretions like
|
|
1493
1566
|
* `PostgresSchema` or `SqliteUnboundDatabase`; the factory is the
|
|
@@ -1499,14 +1572,8 @@ export type ContractInput<
|
|
|
1499
1572
|
* `StorageTable.namespaceId` referenced by a model, and the
|
|
1500
1573
|
* framework `UNBOUND_NAMESPACE_ID` sentinel (always present so the
|
|
1501
1574
|
* late-bound slot stays available regardless of authoring choices).
|
|
1502
|
-
*
|
|
1503
|
-
* When omitted, the family layer falls back to its placeholder
|
|
1504
|
-
* `SqlUnboundNamespace` singleton for the unbound slot and rejects
|
|
1505
|
-
* any non-unbound coordinate — single-namespace contracts authored
|
|
1506
|
-
* before targets ship their factory stay byte-stable; multi-namespace
|
|
1507
|
-
* contracts must pass the factory through.
|
|
1508
1575
|
*/
|
|
1509
|
-
readonly createNamespace
|
|
1576
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
1510
1577
|
readonly types?: Types;
|
|
1511
1578
|
readonly models?: Models;
|
|
1512
1579
|
readonly codecLookup?: CodecLookup;
|