@prisma-next/sql-contract-ts 0.14.0-dev.4 → 0.14.0-dev.40
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-B4yaUmSw.mjs} +20 -19
- package/dist/build-contract-B4yaUmSw.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 +12 -70
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +10 -10
- package/src/build-contract.ts +34 -37
- 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.40",
|
|
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.40",
|
|
10
|
+
"@prisma-next/contract": "0.14.0-dev.40",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.14.0-dev.40",
|
|
12
|
+
"@prisma-next/framework-components": "0.14.0-dev.40",
|
|
13
|
+
"@prisma-next/sql-contract": "0.14.0-dev.40",
|
|
14
|
+
"@prisma-next/utils": "0.14.0-dev.40",
|
|
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.40",
|
|
21
|
+
"@prisma-next/tsconfig": "0.14.0-dev.40",
|
|
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.40",
|
|
25
25
|
"tsdown": "0.22.1",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.8"
|
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,24 +247,17 @@ 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
|
|
|
252
256
|
return {
|
|
253
257
|
nativeType: field.descriptor.nativeType,
|
|
254
258
|
codecId,
|
|
255
259
|
nullable: field.nullable,
|
|
260
|
+
...(field.many ? { many: true as const } : {}),
|
|
256
261
|
...ifDefined('typeParams', field.descriptor.typeParams),
|
|
257
262
|
...ifDefined('default', encodedDefault),
|
|
258
263
|
...ifDefined('typeRef', field.descriptor.typeRef),
|
|
@@ -308,18 +313,15 @@ function ensureUnboundNamespaceSlot(
|
|
|
308
313
|
if (Object.hasOwn(namespaces, UNBOUND_NAMESPACE_ID)) {
|
|
309
314
|
return namespaces;
|
|
310
315
|
}
|
|
311
|
-
const unboundInput:
|
|
316
|
+
const unboundInput: SqlNamespaceInput = {
|
|
312
317
|
id: UNBOUND_NAMESPACE_ID,
|
|
313
318
|
entries: { table: {} },
|
|
314
319
|
};
|
|
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
|
-
>({
|
|
320
|
+
const unbound = createNamespace(unboundInput);
|
|
321
|
+
return {
|
|
320
322
|
[UNBOUND_NAMESPACE_ID]: unbound,
|
|
321
323
|
...namespaces,
|
|
322
|
-
}
|
|
324
|
+
};
|
|
323
325
|
}
|
|
324
326
|
|
|
325
327
|
export function buildSqlContractFromDefinition(
|
|
@@ -729,25 +731,20 @@ export function buildSqlContractFromDefinition(
|
|
|
729
731
|
}
|
|
730
732
|
|
|
731
733
|
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
|
-
),
|
|
734
|
+
const namespaces: SqlStorageInput['namespaces'] = Object.fromEntries(
|
|
735
|
+
[...namespaceCoordinateIds].sort().map((id) => {
|
|
736
|
+
const valueSetEntries = storageValueSetsByNs[id];
|
|
737
|
+
const nsInput: SqlNamespaceInput = {
|
|
738
|
+
id,
|
|
739
|
+
entries: {
|
|
740
|
+
table: tablesByNamespace[id] ?? {},
|
|
741
|
+
...(valueSetEntries !== undefined && Object.keys(valueSetEntries).length > 0
|
|
742
|
+
? { valueSet: valueSetEntries }
|
|
743
|
+
: {}),
|
|
744
|
+
},
|
|
745
|
+
};
|
|
746
|
+
return [id, createNamespace(nsInput)];
|
|
747
|
+
}),
|
|
751
748
|
);
|
|
752
749
|
const storageWithoutHash = {
|
|
753
750
|
...(Object.keys(documentTypes).length > 0 ? { types: documentTypes } : {}),
|
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;
|
package/src/contract-lowering.ts
CHANGED
|
@@ -727,6 +727,7 @@ function resolveModelNode(
|
|
|
727
727
|
columnName,
|
|
728
728
|
descriptor,
|
|
729
729
|
nullable: fieldState.nullable,
|
|
730
|
+
...(fieldState.many === true ? { many: true } : {}),
|
|
730
731
|
...(fieldState.default ? { default: fieldState.default } : {}),
|
|
731
732
|
...(fieldState.executionDefaults ? { executionDefaults: fieldState.executionDefaults } : {}),
|
|
732
733
|
...(enumHandle !== undefined ? { enumTypeHandle: enumHandle } : {}),
|
|
@@ -877,7 +878,7 @@ export function buildContractDefinition(definition: ContractInput): ContractDefi
|
|
|
877
878
|
? { storageTypes: collection.storageTypes }
|
|
878
879
|
: {}),
|
|
879
880
|
...(definition.namespaces ? { namespaces: definition.namespaces } : {}),
|
|
880
|
-
|
|
881
|
+
createNamespace: definition.createNamespace,
|
|
881
882
|
...(definition.enums && Object.keys(definition.enums).length > 0
|
|
882
883
|
? { enums: definition.enums }
|
|
883
884
|
: {}),
|