@prisma-next/sql-contract-ts 0.14.0-dev.3 → 0.14.0-dev.31
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-DyyzDMK7.mjs} +10 -12
- package/dist/build-contract-DyyzDMK7.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 +16 -8
- 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 +19 -28
- package/src/config-types.ts +10 -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.31",
|
|
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.31",
|
|
10
|
+
"@prisma-next/contract": "0.14.0-dev.31",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.14.0-dev.31",
|
|
12
|
+
"@prisma-next/framework-components": "0.14.0-dev.31",
|
|
13
|
+
"@prisma-next/sql-contract": "0.14.0-dev.31",
|
|
14
|
+
"@prisma-next/utils": "0.14.0-dev.31",
|
|
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.31",
|
|
21
|
+
"@prisma-next/tsconfig": "0.14.0-dev.31",
|
|
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.31",
|
|
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,
|
|
@@ -308,18 +307,15 @@ function ensureUnboundNamespaceSlot(
|
|
|
308
307
|
if (Object.hasOwn(namespaces, UNBOUND_NAMESPACE_ID)) {
|
|
309
308
|
return namespaces;
|
|
310
309
|
}
|
|
311
|
-
const unboundInput:
|
|
310
|
+
const unboundInput: SqlNamespaceInput = {
|
|
312
311
|
id: UNBOUND_NAMESPACE_ID,
|
|
313
312
|
entries: { table: {} },
|
|
314
313
|
};
|
|
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
|
-
>({
|
|
314
|
+
const unbound = createNamespace(unboundInput);
|
|
315
|
+
return {
|
|
320
316
|
[UNBOUND_NAMESPACE_ID]: unbound,
|
|
321
317
|
...namespaces,
|
|
322
|
-
}
|
|
318
|
+
};
|
|
323
319
|
}
|
|
324
320
|
|
|
325
321
|
export function buildSqlContractFromDefinition(
|
|
@@ -729,25 +725,20 @@ export function buildSqlContractFromDefinition(
|
|
|
729
725
|
}
|
|
730
726
|
|
|
731
727
|
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
|
-
),
|
|
728
|
+
const namespaces: SqlStorageInput['namespaces'] = Object.fromEntries(
|
|
729
|
+
[...namespaceCoordinateIds].sort().map((id) => {
|
|
730
|
+
const valueSetEntries = storageValueSetsByNs[id];
|
|
731
|
+
const nsInput: SqlNamespaceInput = {
|
|
732
|
+
id,
|
|
733
|
+
entries: {
|
|
734
|
+
table: tablesByNamespace[id] ?? {},
|
|
735
|
+
...(valueSetEntries !== undefined && Object.keys(valueSetEntries).length > 0
|
|
736
|
+
? { valueSet: valueSetEntries }
|
|
737
|
+
: {}),
|
|
738
|
+
},
|
|
739
|
+
};
|
|
740
|
+
return [id, createNamespace(nsInput)];
|
|
741
|
+
}),
|
|
751
742
|
);
|
|
752
743
|
const storageWithoutHash = {
|
|
753
744
|
...(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,12 +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: {
|
|
36
|
+
sourceFormat: 'typescript',
|
|
34
37
|
load: async () => {
|
|
35
|
-
const built = buildSqlContractFromDefinition({
|
|
38
|
+
const built = buildSqlContractFromDefinition({
|
|
39
|
+
target: options.target,
|
|
40
|
+
createNamespace: options.createNamespace,
|
|
41
|
+
models: [],
|
|
42
|
+
});
|
|
36
43
|
return ok(applySpecifierDefaultControlPolicy(built, options.defaultControlPolicy));
|
|
37
44
|
},
|
|
38
45
|
},
|
|
@@ -47,6 +54,7 @@ export function typescriptContract(
|
|
|
47
54
|
): ContractConfig {
|
|
48
55
|
return {
|
|
49
56
|
source: {
|
|
57
|
+
sourceFormat: 'typescript',
|
|
50
58
|
load: async () =>
|
|
51
59
|
ok(applySpecifierDefaultControlPolicy(contract, options?.defaultControlPolicy)),
|
|
52
60
|
},
|
|
@@ -63,6 +71,7 @@ export function typescriptContractFromPath(
|
|
|
63
71
|
): ContractConfig {
|
|
64
72
|
return {
|
|
65
73
|
source: {
|
|
74
|
+
sourceFormat: 'typescript',
|
|
66
75
|
inputs: [contractPath],
|
|
67
76
|
load: async (context) => {
|
|
68
77
|
const [absolutePath] = context.resolvedInputs;
|
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
|
: {}),
|
package/src/contract-types.ts
CHANGED
|
@@ -21,10 +21,10 @@ import type { UnionToIntersection } from './authoring-type-utils';
|
|
|
21
21
|
import type { AttributeStageIdFieldNames, FieldStateOf, ScalarFieldBuilder } from './contract-dsl';
|
|
22
22
|
import type { EnumTypeHandle } from './enum-type';
|
|
23
23
|
|
|
24
|
-
export type ExtractCodecTypesFromPack<P> = P extends {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
export type ExtractCodecTypesFromPack<P> = P extends {
|
|
25
|
+
__codecTypes?: infer C extends Record<string, { output: unknown }>;
|
|
26
|
+
}
|
|
27
|
+
? C
|
|
28
28
|
: Record<string, never>;
|
|
29
29
|
|
|
30
30
|
export type MergeExtensionCodecTypes<Packs extends Record<string, unknown>> = UnionToIntersection<
|
|
@@ -279,6 +279,8 @@ type FieldNullableOf<FieldState> = FieldState extends {
|
|
|
279
279
|
? Nullable
|
|
280
280
|
: boolean;
|
|
281
281
|
|
|
282
|
+
type FieldManyOf<FieldState> = FieldState extends { readonly many?: true } ? true : false;
|
|
283
|
+
|
|
282
284
|
type FieldColumnOverrideOf<FieldState> = Present<
|
|
283
285
|
FieldState extends { readonly columnName?: infer ColumnName } ? ColumnName : never
|
|
284
286
|
>;
|
|
@@ -471,15 +473,17 @@ type StorageColumn<
|
|
|
471
473
|
NativeType extends string,
|
|
472
474
|
TypeRef extends string | undefined = undefined,
|
|
473
475
|
TypeParams extends Record<string, unknown> | undefined = undefined,
|
|
476
|
+
Many extends boolean = false,
|
|
474
477
|
> = {
|
|
475
478
|
readonly nativeType: NativeType;
|
|
476
479
|
readonly codecId: CodecId;
|
|
477
480
|
readonly nullable: Nullable;
|
|
478
481
|
readonly default?: ColumnDefault;
|
|
479
|
-
} & (TypeRef extends string ? { readonly typeRef: TypeRef } : Record<
|
|
482
|
+
} & (TypeRef extends string ? { readonly typeRef: TypeRef } : Record<never, never>) &
|
|
480
483
|
(TypeParams extends Record<string, unknown>
|
|
481
484
|
? { readonly typeParams: TypeParams }
|
|
482
|
-
: Record<
|
|
485
|
+
: Record<never, never>) &
|
|
486
|
+
(Many extends true ? { readonly many: true } : Record<never, never>);
|
|
483
487
|
|
|
484
488
|
type ModelStorageColumn<
|
|
485
489
|
Definition,
|
|
@@ -496,7 +500,8 @@ type ModelStorageColumn<
|
|
|
496
500
|
ResolveFieldDescriptor<Definition, ModelFieldState<Definition, ModelName, FieldName>>
|
|
497
501
|
>,
|
|
498
502
|
ResolveFieldColumnTypeRef<Definition, ModelFieldState<Definition, ModelName, FieldName>>,
|
|
499
|
-
ResolveFieldColumnTypeParams<Definition, ModelFieldState<Definition, ModelName, FieldName
|
|
503
|
+
ResolveFieldColumnTypeParams<Definition, ModelFieldState<Definition, ModelName, FieldName>>,
|
|
504
|
+
FieldManyOf<ModelFieldState<Definition, ModelName, FieldName>>
|
|
500
505
|
>
|
|
501
506
|
: never;
|
|
502
507
|
|
|
@@ -677,6 +682,8 @@ type BuiltStorage<Definition> = {
|
|
|
677
682
|
};
|
|
678
683
|
};
|
|
679
684
|
|
|
685
|
+
type StorageColumnManyOf<Col> = Col extends { readonly many: true } ? true : false;
|
|
686
|
+
|
|
680
687
|
// The enum value union for an enum-typed field, or `never` for a non-enum
|
|
681
688
|
// field. The field's `typeRef` carries the authored `EnumTypeHandle`, whose
|
|
682
689
|
// `Values` tuple preserves the literal member values (text or numeric).
|
|
@@ -698,7 +705,9 @@ type CodecChannelType<
|
|
|
698
705
|
> = ModelStorageColumn<Definition, ModelName, FieldName>['codecId'] extends infer Id extends
|
|
699
706
|
keyof CodecTypesFromDefinition<Definition>
|
|
700
707
|
? CodecTypesFromDefinition<Definition>[Id] extends { readonly [K in Channel]: infer T }
|
|
701
|
-
?
|
|
708
|
+
? StorageColumnManyOf<ModelStorageColumn<Definition, ModelName, FieldName>> extends true
|
|
709
|
+
? ReadonlyArray<T>
|
|
710
|
+
: T
|
|
702
711
|
: unknown
|
|
703
712
|
: unknown;
|
|
704
713
|
|
|
@@ -712,7 +721,9 @@ type FieldChannelType<
|
|
|
712
721
|
> =
|
|
713
722
|
| ([EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>] extends [never]
|
|
714
723
|
? CodecChannelType<Definition, ModelName, FieldName, Channel>
|
|
715
|
-
:
|
|
724
|
+
: StorageColumnManyOf<ModelStorageColumn<Definition, ModelName, FieldName>> extends true
|
|
725
|
+
? ReadonlyArray<EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>>
|
|
726
|
+
: EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>)
|
|
716
727
|
| (FieldNullableOf<ModelFieldState<Definition, ModelName, FieldName>> extends true
|
|
717
728
|
? null
|
|
718
729
|
: never);
|
|
@@ -735,6 +746,17 @@ type FieldChannelTypes<Definition, Channel extends 'output' | 'input'> = {
|
|
|
735
746
|
};
|
|
736
747
|
};
|
|
737
748
|
|
|
749
|
+
type StorageColumnChannelTypes<Definition, Channel extends 'output' | 'input'> = {
|
|
750
|
+
readonly [Ns in DefaultStorageNamespaceId<Definition>]: {
|
|
751
|
+
readonly [ModelName in ModelNames<Definition> as BuiltModelTableName<Definition, ModelName>]: {
|
|
752
|
+
readonly [FieldName in ModelFieldNames<Definition, ModelName> as BuiltModelColumnMappings<
|
|
753
|
+
Definition,
|
|
754
|
+
ModelName
|
|
755
|
+
>[FieldName]['column']]: FieldChannelType<Definition, ModelName, FieldName, Channel>;
|
|
756
|
+
};
|
|
757
|
+
};
|
|
758
|
+
};
|
|
759
|
+
|
|
738
760
|
export type SqlContractResult<Definition> = ContractWithTypeMaps<
|
|
739
761
|
Omit<Contract<BuiltStorage<Definition>>, 'domain'> & {
|
|
740
762
|
readonly target: DefinitionTargetId<Definition>;
|
|
@@ -754,6 +776,8 @@ export type SqlContractResult<Definition> = ContractWithTypeMaps<
|
|
|
754
776
|
CodecTypesFromDefinition<Definition>,
|
|
755
777
|
Record<string, never>,
|
|
756
778
|
FieldChannelTypes<Definition, 'output'>,
|
|
757
|
-
FieldChannelTypes<Definition, 'input'
|
|
779
|
+
FieldChannelTypes<Definition, 'input'>,
|
|
780
|
+
StorageColumnChannelTypes<Definition, 'output'>,
|
|
781
|
+
StorageColumnChannelTypes<Definition, 'input'>
|
|
758
782
|
>
|
|
759
783
|
>;
|