@prisma-next/sql-contract-ts 0.14.0-dev.6 → 0.14.0-dev.60
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-CSyrbCoJ.mjs} +239 -30
- package/dist/build-contract-CSyrbCoJ.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 +231 -328
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +43 -75
- 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 +402 -49
- package/src/composed-authoring-helpers.ts +3 -6
- package/src/config-types.ts +7 -1
- package/src/contract-builder.ts +71 -5
- package/src/contract-definition.ts +27 -4
- package/src/contract-dsl.ts +117 -41
- package/src/contract-lowering.ts +5 -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/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';
|
|
@@ -15,6 +18,7 @@ import {
|
|
|
15
18
|
type ComposedAuthoringHelpers,
|
|
16
19
|
createComposedAuthoringHelpers,
|
|
17
20
|
} from './composed-authoring-helpers';
|
|
21
|
+
import type { PackEntitiesInput } from './contract-definition';
|
|
18
22
|
import {
|
|
19
23
|
type ContractInput,
|
|
20
24
|
type ContractModelBuilder,
|
|
@@ -68,11 +72,12 @@ type ContractDefinition<
|
|
|
68
72
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
69
73
|
readonly defaultControlPolicy?: ControlPolicy;
|
|
70
74
|
readonly namespaces?: Namespaces;
|
|
71
|
-
readonly createNamespace
|
|
75
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
72
76
|
readonly types?: Types;
|
|
73
77
|
readonly models?: Models;
|
|
74
78
|
readonly codecLookup?: CodecLookup;
|
|
75
79
|
readonly enums?: Enums;
|
|
80
|
+
readonly packEntities?: PackEntitiesInput;
|
|
76
81
|
};
|
|
77
82
|
|
|
78
83
|
type ContractScaffold<
|
|
@@ -93,11 +98,12 @@ type ContractScaffold<
|
|
|
93
98
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
94
99
|
readonly defaultControlPolicy?: ControlPolicy;
|
|
95
100
|
readonly namespaces?: Namespaces;
|
|
96
|
-
readonly createNamespace
|
|
101
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
97
102
|
readonly types?: never;
|
|
98
103
|
readonly models?: never;
|
|
99
104
|
readonly codecLookup?: CodecLookup;
|
|
100
105
|
readonly enums?: Enums;
|
|
106
|
+
readonly packEntities?: PackEntitiesInput;
|
|
101
107
|
};
|
|
102
108
|
|
|
103
109
|
type ContractFactory<
|
|
@@ -111,6 +117,7 @@ type ContractFactory<
|
|
|
111
117
|
readonly types?: Types;
|
|
112
118
|
readonly models?: Models;
|
|
113
119
|
readonly enums?: Enums;
|
|
120
|
+
readonly packEntities?: PackEntitiesInput;
|
|
114
121
|
};
|
|
115
122
|
|
|
116
123
|
function validateTargetPackRef(
|
|
@@ -314,11 +321,12 @@ type BoundDefinitionInput<
|
|
|
314
321
|
readonly foreignKeyDefaults?: ForeignKeyDefaults;
|
|
315
322
|
readonly defaultControlPolicy?: ControlPolicy;
|
|
316
323
|
readonly namespaces?: Namespaces;
|
|
317
|
-
readonly createNamespace
|
|
324
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
318
325
|
readonly types?: Types;
|
|
319
326
|
readonly models?: Models;
|
|
320
327
|
readonly codecLookup?: CodecLookup;
|
|
321
328
|
readonly enums?: Record<string, EnumTypeHandle>;
|
|
329
|
+
readonly packEntities?: PackEntitiesInput;
|
|
322
330
|
};
|
|
323
331
|
|
|
324
332
|
// A bare `Record<string, EnumTypeHandle>` (no literal keys) is the widened
|
|
@@ -342,6 +350,60 @@ type WithFamilyTarget<
|
|
|
342
350
|
T extends TargetPackRef<'sql', string>,
|
|
343
351
|
> = Input & { readonly family: F; readonly target: T };
|
|
344
352
|
|
|
353
|
+
// Deep-merges packEntities authored on the scaffold definition with those
|
|
354
|
+
// returned from the factory callback — three levels deep (namespace, kind,
|
|
355
|
+
// name), unlike `enums`' flat shallow merge, since a factory-declared
|
|
356
|
+
// namespace/kind must not silently drop a scaffold-declared sibling entry
|
|
357
|
+
// under the same namespace or kind. A same-name key present on both sides is
|
|
358
|
+
// only merged when it is the identical entity instance; two *different*
|
|
359
|
+
// entities of the same namespace/kind/name is a collision (the emitted
|
|
360
|
+
// entry could reflect only one), rejected here the same way
|
|
361
|
+
// `mergeCollectedPackEntities` in `build-contract.ts` rejects it.
|
|
362
|
+
function mergePackEntityNames(
|
|
363
|
+
namespaceId: string,
|
|
364
|
+
kind: string,
|
|
365
|
+
a: Readonly<Record<string, unknown>> | undefined,
|
|
366
|
+
b: Readonly<Record<string, unknown>> | undefined,
|
|
367
|
+
): Readonly<Record<string, unknown>> {
|
|
368
|
+
if (a !== undefined && b !== undefined) {
|
|
369
|
+
for (const [name, entity] of Object.entries(b)) {
|
|
370
|
+
const existing = a[name];
|
|
371
|
+
if (existing !== undefined && existing !== entity) {
|
|
372
|
+
throw new Error(
|
|
373
|
+
`defineContract: two different "${kind}" entities named "${name}" in namespace "${namespaceId}" — a factory-returned pack entity conflicts with a scaffold-declared one; pack-entity names must be unique per namespace.`,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return { ...(a ?? {}), ...(b ?? {}) };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function mergePackEntityKinds(
|
|
382
|
+
namespaceId: string,
|
|
383
|
+
a: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
|
|
384
|
+
b: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
|
|
385
|
+
): Readonly<Record<string, Readonly<Record<string, unknown>>>> {
|
|
386
|
+
const kinds = new Set([...Object.keys(a ?? {}), ...Object.keys(b ?? {})]);
|
|
387
|
+
const result: Record<string, Readonly<Record<string, unknown>>> = {};
|
|
388
|
+
for (const kind of kinds) {
|
|
389
|
+
result[kind] = mergePackEntityNames(namespaceId, kind, a?.[kind], b?.[kind]);
|
|
390
|
+
}
|
|
391
|
+
return result;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function mergePackEntities(
|
|
395
|
+
a: PackEntitiesInput | undefined,
|
|
396
|
+
b: PackEntitiesInput | undefined,
|
|
397
|
+
): PackEntitiesInput | undefined {
|
|
398
|
+
if (a === undefined && b === undefined) return undefined;
|
|
399
|
+
const namespaces = new Set([...Object.keys(a ?? {}), ...Object.keys(b ?? {})]);
|
|
400
|
+
const result: Record<string, Readonly<Record<string, Readonly<Record<string, unknown>>>>> = {};
|
|
401
|
+
for (const namespaceId of namespaces) {
|
|
402
|
+
result[namespaceId] = mergePackEntityKinds(namespaceId, a?.[namespaceId], b?.[namespaceId]);
|
|
403
|
+
}
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
|
|
345
407
|
/**
|
|
346
408
|
* Shared builder that assembles a SqlContract with pre-bound family and target.
|
|
347
409
|
* Extension wrappers keep their own public overloads and delegate their impl body here;
|
|
@@ -387,6 +449,7 @@ export function buildBoundContract<
|
|
|
387
449
|
readonly types?: Record<string, StorageTypeInstance>;
|
|
388
450
|
readonly models?: Record<string, ModelLike>;
|
|
389
451
|
readonly enums?: Record<string, EnumTypeHandle>;
|
|
452
|
+
readonly packEntities?: PackEntitiesInput;
|
|
390
453
|
},
|
|
391
454
|
>(
|
|
392
455
|
family: F,
|
|
@@ -412,6 +475,7 @@ export function buildBoundContract(
|
|
|
412
475
|
readonly types?: Record<string, StorageTypeInstance>;
|
|
413
476
|
readonly models?: Record<string, ModelLike>;
|
|
414
477
|
readonly enums?: Record<string, EnumTypeHandle>;
|
|
478
|
+
readonly packEntities?: PackEntitiesInput;
|
|
415
479
|
})
|
|
416
480
|
| undefined,
|
|
417
481
|
) {
|
|
@@ -426,11 +490,13 @@ export function buildBoundContract(
|
|
|
426
490
|
}),
|
|
427
491
|
);
|
|
428
492
|
const mergedEnums = { ...(definition.enums ?? {}), ...built.enums };
|
|
493
|
+
const mergedPackEntities = mergePackEntities(definition.packEntities, built.packEntities);
|
|
429
494
|
return buildContractFromDsl({
|
|
430
495
|
...full,
|
|
431
496
|
...ifDefined('types', built.types),
|
|
432
497
|
...ifDefined('models', built.models),
|
|
433
498
|
...ifDefined('enums', Object.keys(mergedEnums).length > 0 ? mergedEnums : undefined),
|
|
499
|
+
...ifDefined('packEntities', mergedPackEntities),
|
|
434
500
|
});
|
|
435
501
|
}
|
|
436
502
|
|
|
@@ -6,16 +6,30 @@ 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';
|
|
16
16
|
|
|
17
17
|
export type { ExecutionMutationDefaultPhases };
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* An author-declared, namespace-scoped pack entity attachment: namespace id →
|
|
21
|
+
* entity kind (the discriminator the target/extension pack registered its
|
|
22
|
+
* `AuthoringContributions.entityTypes` descriptor under, e.g. `native_enum`)
|
|
23
|
+
* → entity name → the lowered entity instance. Generic on purpose — neither
|
|
24
|
+
* the framework nor `contract-ts` names a specific entity kind here; the
|
|
25
|
+
* shape mirrors `SqlNamespaceInput.entries` (`entries.<kind>[name]`), just
|
|
26
|
+
* namespace-nested so an author can target any declared namespace (default
|
|
27
|
+
* or named), not only the contract's default namespace.
|
|
28
|
+
*/
|
|
29
|
+
export type PackEntitiesInput = Readonly<
|
|
30
|
+
Record<string, Readonly<Record<string, Readonly<Record<string, unknown>>>>>
|
|
31
|
+
>;
|
|
32
|
+
|
|
19
33
|
export interface FieldNode {
|
|
20
34
|
readonly fieldName: string;
|
|
21
35
|
readonly columnName: string;
|
|
@@ -175,8 +189,8 @@ export interface ContractDefinition {
|
|
|
175
189
|
* `SqlStorage.namespaces` together with `createNamespace`.
|
|
176
190
|
*/
|
|
177
191
|
readonly namespaces?: readonly string[];
|
|
178
|
-
/** Target-supplied factory that materialises a `
|
|
179
|
-
readonly createNamespace
|
|
192
|
+
/** Target-supplied factory that materialises a `SqlNamespaceBase` concretion for a declared namespace coordinate. */
|
|
193
|
+
readonly createNamespace: (input: SqlNamespaceInput) => SqlNamespaceBase;
|
|
180
194
|
readonly models: readonly ModelNode[];
|
|
181
195
|
readonly valueObjects?: readonly ValueObjectNode[];
|
|
182
196
|
/**
|
|
@@ -185,4 +199,13 @@ export interface ContractDefinition {
|
|
|
185
199
|
* default namespace.
|
|
186
200
|
*/
|
|
187
201
|
readonly enums?: Record<string, EnumTypeHandle>;
|
|
202
|
+
/**
|
|
203
|
+
* Author-declared pack entities, keyed by namespace then entity kind then
|
|
204
|
+
* name. Each entity lowers into `storage.namespaces[ns].entries.<kind>`;
|
|
205
|
+
* when the registered entity-type descriptor's factory output implements
|
|
206
|
+
* the `SqlValueSetDerivingEntityTypeOutput.deriveValueSet` hook, the
|
|
207
|
+
* derived value-set also folds into `entries.valueSet`, mirroring how
|
|
208
|
+
* `enums` flows there.
|
|
209
|
+
*/
|
|
210
|
+
readonly packEntities?: PackEntitiesInput;
|
|
188
211
|
}
|
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
|
|
232
|
+
>
|
|
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
|
|
218
246
|
>
|
|
219
|
-
? ScalarFieldState<CodecId, TypeRef, Nullable, ColumnName, IdSpec, UniqueSpec>
|
|
220
|
-
:
|
|
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;
|
|
@@ -1516,6 +1583,15 @@ export type ContractInput<
|
|
|
1516
1583
|
* default namespace. Fields reference the enum via `field.namedType(handle)`.
|
|
1517
1584
|
*/
|
|
1518
1585
|
readonly enums?: Record<string, import('./enum-type').EnumTypeHandle>;
|
|
1586
|
+
/**
|
|
1587
|
+
* Author-declared pack entities, keyed by namespace id then entity kind
|
|
1588
|
+
* then name — e.g. `{ auth: { native_enum: { AalLevel: <entity> } } }`.
|
|
1589
|
+
* Each entity lowers into `storage.namespaces[ns].entries.<kind>`; when its
|
|
1590
|
+
* registered entity-type descriptor derives a value-set, that also folds
|
|
1591
|
+
* into `entries.valueSet`, mirroring how `enums` flows there. Generic on
|
|
1592
|
+
* purpose — neither this type nor the assembler names a specific kind.
|
|
1593
|
+
*/
|
|
1594
|
+
readonly packEntities?: import('./contract-definition').PackEntitiesInput;
|
|
1519
1595
|
};
|
|
1520
1596
|
|
|
1521
1597
|
export function model<
|
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,10 +878,13 @@ 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
|
: {}),
|
|
885
|
+
...(definition.packEntities && Object.keys(definition.packEntities).length > 0
|
|
886
|
+
? { packEntities: definition.packEntities }
|
|
887
|
+
: {}),
|
|
884
888
|
models,
|
|
885
889
|
};
|
|
886
890
|
}
|