@prisma-next/sql-contract-ts 0.13.0-dev.2 → 0.13.0-dev.20
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/README.md +5 -5
- package/dist/{build-contract-C-x2pfu4.mjs → build-contract-ZpcEhQq3.mjs} +13 -10
- package/dist/build-contract-ZpcEhQq3.mjs.map +1 -0
- package/dist/config-types.mjs +1 -1
- package/dist/contract-builder.d.mts +102 -36
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +41 -7
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +10 -10
- package/src/build-contract.ts +15 -14
- package/src/contract-builder.ts +36 -7
- package/src/contract-dsl.ts +39 -8
- package/src/contract-types.ts +105 -26
- package/src/enum-type.ts +98 -28
- package/src/exports/contract-builder.ts +10 -2
- package/dist/build-contract-C-x2pfu4.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.13.0-dev.
|
|
3
|
+
"version": "0.13.0-dev.20",
|
|
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.13.0-dev.
|
|
10
|
-
"@prisma-next/contract": "0.13.0-dev.
|
|
11
|
-
"@prisma-next/contract-authoring": "0.13.0-dev.
|
|
12
|
-
"@prisma-next/framework-components": "0.13.0-dev.
|
|
13
|
-
"@prisma-next/sql-contract": "0.13.0-dev.
|
|
14
|
-
"@prisma-next/utils": "0.13.0-dev.
|
|
9
|
+
"@prisma-next/config": "0.13.0-dev.20",
|
|
10
|
+
"@prisma-next/contract": "0.13.0-dev.20",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.13.0-dev.20",
|
|
12
|
+
"@prisma-next/framework-components": "0.13.0-dev.20",
|
|
13
|
+
"@prisma-next/sql-contract": "0.13.0-dev.20",
|
|
14
|
+
"@prisma-next/utils": "0.13.0-dev.20",
|
|
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.13.0-dev.
|
|
21
|
-
"@prisma-next/tsconfig": "0.13.0-dev.
|
|
20
|
+
"@prisma-next/test-utils": "0.13.0-dev.20",
|
|
21
|
+
"@prisma-next/tsconfig": "0.13.0-dev.20",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.21.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.13.0-dev.
|
|
24
|
+
"@prisma-next/tsdown": "0.13.0-dev.20",
|
|
25
25
|
"tsdown": "0.22.1",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.8"
|
package/src/build-contract.ts
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
asNamespaceId,
|
|
8
8
|
type ColumnDefault,
|
|
9
|
-
type ColumnDefaultLiteralInputValue,
|
|
10
9
|
type Contract,
|
|
11
10
|
type ContractEnum,
|
|
12
11
|
type ContractField,
|
|
@@ -63,16 +62,15 @@ type DomainFieldRef =
|
|
|
63
62
|
| { readonly kind: 'scalar'; readonly many?: boolean }
|
|
64
63
|
| { readonly kind: 'valueObject'; readonly name: string; readonly many?: boolean };
|
|
65
64
|
|
|
66
|
-
function
|
|
67
|
-
value: ColumnDefaultLiteralInputValue,
|
|
68
|
-
codecId: string,
|
|
69
|
-
codecLookup?: CodecLookup,
|
|
70
|
-
): JsonValue {
|
|
65
|
+
function encodeViaCodec(value: unknown, codecId: string, codecLookup?: CodecLookup): JsonValue {
|
|
71
66
|
const codec = codecLookup?.get(codecId);
|
|
72
67
|
if (codec) {
|
|
73
68
|
return codec.encodeJson(value);
|
|
74
69
|
}
|
|
75
|
-
return
|
|
70
|
+
return blindCast<
|
|
71
|
+
JsonValue,
|
|
72
|
+
'no codec lookup at build time: literal/enum member value is already JSON-safe'
|
|
73
|
+
>(value);
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
function encodeColumnDefault(
|
|
@@ -85,7 +83,7 @@ function encodeColumnDefault(
|
|
|
85
83
|
}
|
|
86
84
|
return {
|
|
87
85
|
kind: 'literal',
|
|
88
|
-
value:
|
|
86
|
+
value: encodeViaCodec(defaultInput.value, codecId, codecLookup),
|
|
89
87
|
};
|
|
90
88
|
}
|
|
91
89
|
|
|
@@ -451,9 +449,9 @@ export function buildSqlContractFromDefinition(
|
|
|
451
449
|
enumHandle !== undefined
|
|
452
450
|
? {
|
|
453
451
|
plane: 'storage',
|
|
454
|
-
entityKind: '
|
|
452
|
+
entityKind: 'valueSet',
|
|
455
453
|
namespaceId: defaultNamespaceId,
|
|
456
|
-
|
|
454
|
+
entityName: enumHandle.enumName,
|
|
457
455
|
}
|
|
458
456
|
: undefined;
|
|
459
457
|
const domainValueSetRef: ValueSetRef | undefined =
|
|
@@ -462,7 +460,7 @@ export function buildSqlContractFromDefinition(
|
|
|
462
460
|
plane: 'domain',
|
|
463
461
|
entityKind: 'enum',
|
|
464
462
|
namespaceId: defaultNamespaceId,
|
|
465
|
-
|
|
463
|
+
entityName: enumHandle.enumName,
|
|
466
464
|
}
|
|
467
465
|
: undefined;
|
|
468
466
|
|
|
@@ -771,7 +769,10 @@ export function buildSqlContractFromDefinition(
|
|
|
771
769
|
}
|
|
772
770
|
domainSlot[enumName] = {
|
|
773
771
|
codecId: handle.codecId,
|
|
774
|
-
members: handle.enumMembers
|
|
772
|
+
members: handle.enumMembers.map((m) => ({
|
|
773
|
+
name: m.name,
|
|
774
|
+
value: encodeViaCodec(m.value, handle.codecId, codecLookup),
|
|
775
|
+
})),
|
|
775
776
|
};
|
|
776
777
|
|
|
777
778
|
let storageSlot = storageValueSetsByNs[nsId];
|
|
@@ -780,8 +781,8 @@ export function buildSqlContractFromDefinition(
|
|
|
780
781
|
storageValueSetsByNs[nsId] = storageSlot;
|
|
781
782
|
}
|
|
782
783
|
storageSlot[enumName] = {
|
|
783
|
-
kind: '
|
|
784
|
-
values: handle.values,
|
|
784
|
+
kind: 'valueSet',
|
|
785
|
+
values: handle.values.map((v) => encodeViaCodec(v, handle.codecId, codecLookup)),
|
|
785
786
|
};
|
|
786
787
|
}
|
|
787
788
|
|
package/src/contract-builder.ts
CHANGED
|
@@ -62,6 +62,7 @@ type ContractDefinition<
|
|
|
62
62
|
StorageHash extends string | undefined,
|
|
63
63
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
64
64
|
Namespaces extends readonly string[] | undefined = undefined,
|
|
65
|
+
Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
65
66
|
> = {
|
|
66
67
|
readonly family: Family;
|
|
67
68
|
readonly target: Target;
|
|
@@ -75,7 +76,7 @@ type ContractDefinition<
|
|
|
75
76
|
readonly types?: Types;
|
|
76
77
|
readonly models?: Models;
|
|
77
78
|
readonly codecLookup?: CodecLookup;
|
|
78
|
-
readonly enums?:
|
|
79
|
+
readonly enums?: Enums;
|
|
79
80
|
};
|
|
80
81
|
|
|
81
82
|
type ContractScaffold<
|
|
@@ -86,6 +87,7 @@ type ContractScaffold<
|
|
|
86
87
|
StorageHash extends string | undefined,
|
|
87
88
|
ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined,
|
|
88
89
|
Namespaces extends readonly string[] | undefined = undefined,
|
|
90
|
+
Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
89
91
|
> = {
|
|
90
92
|
readonly family: Family;
|
|
91
93
|
readonly target: Target;
|
|
@@ -99,7 +101,7 @@ type ContractScaffold<
|
|
|
99
101
|
readonly types?: never;
|
|
100
102
|
readonly models?: never;
|
|
101
103
|
readonly codecLookup?: CodecLookup;
|
|
102
|
-
readonly enums?:
|
|
104
|
+
readonly enums?: Enums;
|
|
103
105
|
};
|
|
104
106
|
|
|
105
107
|
type ContractFactory<
|
|
@@ -108,9 +110,11 @@ type ContractFactory<
|
|
|
108
110
|
Types extends Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
109
111
|
Models extends Record<string, ModelLike>,
|
|
110
112
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
113
|
+
Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
111
114
|
> = (helpers: ComposedAuthoringHelpers<Family, Target, ExtensionPacks>) => {
|
|
112
115
|
readonly types?: Types;
|
|
113
116
|
readonly models?: Models;
|
|
117
|
+
readonly enums?: Enums;
|
|
114
118
|
};
|
|
115
119
|
|
|
116
120
|
function validateTargetPackRef(
|
|
@@ -324,6 +328,20 @@ type BoundDefinitionInput<
|
|
|
324
328
|
readonly enums?: Record<string, EnumTypeHandle>;
|
|
325
329
|
};
|
|
326
330
|
|
|
331
|
+
// A bare `Record<string, EnumTypeHandle>` (no literal keys) is the widened
|
|
332
|
+
// default for a side that declared no enums; drop it so the merge keeps only
|
|
333
|
+
// literally-authored enum handles.
|
|
334
|
+
type LiteralEnums<E extends Record<string, EnumTypeHandle>> = string extends keyof E
|
|
335
|
+
? Record<never, never>
|
|
336
|
+
: E;
|
|
337
|
+
|
|
338
|
+
// Merges enum handles authored on the scaffold definition with those returned
|
|
339
|
+
// from the factory callback. Either side may be the widened default (empty).
|
|
340
|
+
export type MergeEnums<
|
|
341
|
+
ScaffoldEnums extends Record<string, EnumTypeHandle>,
|
|
342
|
+
FactoryEnums extends Record<string, EnumTypeHandle>,
|
|
343
|
+
> = LiteralEnums<ScaffoldEnums> & LiteralEnums<FactoryEnums>;
|
|
344
|
+
|
|
327
345
|
// Merges a bound input with the pre-bound family/target to produce a full ContractDefinition.
|
|
328
346
|
type WithFamilyTarget<
|
|
329
347
|
Input,
|
|
@@ -375,6 +393,7 @@ export function buildBoundContract<
|
|
|
375
393
|
const Built extends {
|
|
376
394
|
readonly types?: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>;
|
|
377
395
|
readonly models?: Record<string, ModelLike>;
|
|
396
|
+
readonly enums?: Record<string, EnumTypeHandle>;
|
|
378
397
|
},
|
|
379
398
|
>(
|
|
380
399
|
family: F,
|
|
@@ -399,6 +418,7 @@ export function buildBoundContract(
|
|
|
399
418
|
) => {
|
|
400
419
|
readonly types?: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>;
|
|
401
420
|
readonly models?: Record<string, ModelLike>;
|
|
421
|
+
readonly enums?: Record<string, EnumTypeHandle>;
|
|
402
422
|
})
|
|
403
423
|
| undefined,
|
|
404
424
|
) {
|
|
@@ -412,10 +432,12 @@ export function buildBoundContract(
|
|
|
412
432
|
extensionPacks: definition.extensionPacks,
|
|
413
433
|
}),
|
|
414
434
|
);
|
|
435
|
+
const mergedEnums = { ...(definition.enums ?? {}), ...built.enums };
|
|
415
436
|
return buildContractFromDsl({
|
|
416
437
|
...full,
|
|
417
438
|
...ifDefined('types', built.types),
|
|
418
439
|
...ifDefined('models', built.models),
|
|
440
|
+
...ifDefined('enums', Object.keys(mergedEnums).length > 0 ? mergedEnums : undefined),
|
|
419
441
|
});
|
|
420
442
|
}
|
|
421
443
|
|
|
@@ -437,6 +459,7 @@ export function defineContract<
|
|
|
437
459
|
const StorageHash extends string | undefined = undefined,
|
|
438
460
|
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
439
461
|
const Namespaces extends readonly string[] | undefined = undefined,
|
|
462
|
+
const Enums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
440
463
|
>(
|
|
441
464
|
definition: ContractDefinition<
|
|
442
465
|
Family,
|
|
@@ -447,7 +470,8 @@ export function defineContract<
|
|
|
447
470
|
Naming,
|
|
448
471
|
StorageHash,
|
|
449
472
|
ForeignKeyDefaults,
|
|
450
|
-
Namespaces
|
|
473
|
+
Namespaces,
|
|
474
|
+
Enums
|
|
451
475
|
>,
|
|
452
476
|
): SqlContractResult<
|
|
453
477
|
ContractDefinition<
|
|
@@ -459,7 +483,8 @@ export function defineContract<
|
|
|
459
483
|
Naming,
|
|
460
484
|
StorageHash,
|
|
461
485
|
ForeignKeyDefaults,
|
|
462
|
-
Namespaces
|
|
486
|
+
Namespaces,
|
|
487
|
+
Enums
|
|
463
488
|
>
|
|
464
489
|
>;
|
|
465
490
|
export function defineContract<
|
|
@@ -477,6 +502,8 @@ export function defineContract<
|
|
|
477
502
|
const StorageHash extends string | undefined = undefined,
|
|
478
503
|
const ForeignKeyDefaults extends ForeignKeyDefaultsState | undefined = undefined,
|
|
479
504
|
const Namespaces extends readonly string[] | undefined = undefined,
|
|
505
|
+
const ScaffoldEnums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
506
|
+
const FactoryEnums extends Record<string, EnumTypeHandle> = Record<string, EnumTypeHandle>,
|
|
480
507
|
>(
|
|
481
508
|
definition: ContractScaffold<
|
|
482
509
|
Family,
|
|
@@ -485,9 +512,10 @@ export function defineContract<
|
|
|
485
512
|
Naming,
|
|
486
513
|
StorageHash,
|
|
487
514
|
ForeignKeyDefaults,
|
|
488
|
-
Namespaces
|
|
515
|
+
Namespaces,
|
|
516
|
+
ScaffoldEnums
|
|
489
517
|
>,
|
|
490
|
-
factory: ContractFactory<Family, Target, Types, Models, ExtensionPacks>,
|
|
518
|
+
factory: ContractFactory<Family, Target, Types, Models, ExtensionPacks, FactoryEnums>,
|
|
491
519
|
): SqlContractResult<
|
|
492
520
|
ContractDefinition<
|
|
493
521
|
Family,
|
|
@@ -498,7 +526,8 @@ export function defineContract<
|
|
|
498
526
|
Naming,
|
|
499
527
|
StorageHash,
|
|
500
528
|
ForeignKeyDefaults,
|
|
501
|
-
Namespaces
|
|
529
|
+
Namespaces,
|
|
530
|
+
MergeEnums<ScaffoldEnums, FactoryEnums>
|
|
502
531
|
>
|
|
503
532
|
>;
|
|
504
533
|
export function defineContract(
|
package/src/contract-dsl.ts
CHANGED
|
@@ -338,6 +338,36 @@ export class ScalarFieldBuilder<State extends AnyScalarFieldState = AnyScalarFie
|
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
+
export class EnumScalarFieldBuilder<
|
|
342
|
+
Handle extends EnumTypeHandle,
|
|
343
|
+
State extends AnyScalarFieldState = ScalarFieldState<Handle['codecId'], Handle, false, undefined>,
|
|
344
|
+
> extends ScalarFieldBuilder<State> {
|
|
345
|
+
readonly #handle: Handle;
|
|
346
|
+
|
|
347
|
+
constructor(state: State, handle: Handle) {
|
|
348
|
+
super(state);
|
|
349
|
+
this.#handle = handle;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
override default(value: Handle['values'][number]): EnumScalarFieldBuilder<Handle, State> {
|
|
353
|
+
return blindCast<
|
|
354
|
+
EnumScalarFieldBuilder<Handle, State>,
|
|
355
|
+
'object spread does not narrow the generic State conditional; runtime shape is correct'
|
|
356
|
+
>(
|
|
357
|
+
new EnumScalarFieldBuilder(
|
|
358
|
+
{ ...this.build(), default: { kind: 'literal', value } },
|
|
359
|
+
this.#handle,
|
|
360
|
+
),
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
override defaultSql(_expression: never): never {
|
|
365
|
+
throw new Error(
|
|
366
|
+
'defaultSql is not available on an enum field; use .default(members.X) instead',
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
341
371
|
function columnField<Descriptor extends ColumnTypeDescriptor>(
|
|
342
372
|
descriptor: Descriptor,
|
|
343
373
|
): ScalarFieldBuilder<ScalarFieldState<Descriptor['codecId'], undefined, false, undefined>> {
|
|
@@ -373,16 +403,17 @@ function namedTypeField<TypeRef extends PostgresEnumStorageEntry>(
|
|
|
373
403
|
): ScalarFieldBuilder<ScalarFieldState<string, TypeRef, false, undefined>>;
|
|
374
404
|
function namedTypeField<Handle extends EnumTypeHandle>(
|
|
375
405
|
typeRef: Handle,
|
|
376
|
-
):
|
|
377
|
-
function namedTypeField(
|
|
378
|
-
typeRef: NamedStorageTypeRef,
|
|
379
|
-
): ScalarFieldBuilder<ScalarFieldState<string, NamedStorageTypeRef, false, undefined>> {
|
|
406
|
+
): EnumScalarFieldBuilder<Handle>;
|
|
407
|
+
function namedTypeField(typeRef: NamedStorageTypeRef): ScalarFieldBuilder {
|
|
380
408
|
if (isEnumTypeHandle(typeRef)) {
|
|
381
|
-
return new
|
|
382
|
-
|
|
409
|
+
return new EnumScalarFieldBuilder(
|
|
410
|
+
{
|
|
411
|
+
kind: 'scalar',
|
|
412
|
+
typeRef,
|
|
413
|
+
nullable: false,
|
|
414
|
+
},
|
|
383
415
|
typeRef,
|
|
384
|
-
|
|
385
|
-
});
|
|
416
|
+
);
|
|
386
417
|
}
|
|
387
418
|
return new ScalarFieldBuilder({
|
|
388
419
|
kind: 'scalar',
|
package/src/contract-types.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
} from '@prisma-next/sql-contract/types';
|
|
18
18
|
import type { UnionToIntersection } from './authoring-type-utils';
|
|
19
19
|
import type { AttributeStageIdFieldNames, FieldStateOf, ScalarFieldBuilder } from './contract-dsl';
|
|
20
|
+
import type { EnumTypeHandle } from './enum-type';
|
|
20
21
|
|
|
21
22
|
export type ExtractCodecTypesFromPack<P> = P extends { __codecTypes?: infer C }
|
|
22
23
|
? C extends Record<string, { output: unknown }>
|
|
@@ -333,17 +334,39 @@ type ResolveNamedStorageType<Definition, TypeRef> =
|
|
|
333
334
|
: StorageTypeInstance
|
|
334
335
|
: StorageTypeInstance;
|
|
335
336
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
337
|
+
// An enum-typed field carries its `EnumTypeHandle` (an object with a `codecId`
|
|
338
|
+
// and `nativeType`, but no `kind`) as the field's `typeRef`. It is neither a
|
|
339
|
+
// string nor a registered `StorageType`, so the named-type lookup cannot reach
|
|
340
|
+
// it; `EnumFieldHandle` short-circuits the resolvers to read codec + native type
|
|
341
|
+
// straight off the handle, with no column type-ref (the enum name is carried
|
|
342
|
+
// elsewhere). The `[...] extends [never]` guard excludes plain column fields,
|
|
343
|
+
// whose `typeRef` is `never`.
|
|
344
|
+
type EnumFieldHandle<FieldState> = [FieldTypeRefOf<FieldState>] extends [never]
|
|
345
|
+
? never
|
|
346
|
+
: FieldTypeRefOf<FieldState> extends EnumTypeHandle
|
|
347
|
+
? FieldTypeRefOf<FieldState>
|
|
348
|
+
: never;
|
|
349
|
+
|
|
350
|
+
type EnumHandleDescriptor<Handle> = Handle extends {
|
|
351
|
+
readonly codecId: infer CodecId extends string;
|
|
352
|
+
readonly nativeType: infer NativeType extends string;
|
|
353
|
+
}
|
|
354
|
+
? { readonly codecId: CodecId; readonly nativeType: NativeType }
|
|
355
|
+
: never;
|
|
341
356
|
|
|
342
|
-
type
|
|
357
|
+
type ResolveFieldDescriptor<Definition, FieldState> = [EnumFieldHandle<FieldState>] extends [never]
|
|
358
|
+
? [FieldDescriptorOf<FieldState>] extends [never]
|
|
359
|
+
? ResolveNamedStorageType<Definition, FieldTypeRefOf<FieldState>>
|
|
360
|
+
: FieldDescriptorOf<FieldState>
|
|
361
|
+
: EnumHandleDescriptor<EnumFieldHandle<FieldState>>;
|
|
362
|
+
|
|
363
|
+
type ResolveFieldColumnTypeRef<Definition, FieldState> = [EnumFieldHandle<FieldState>] extends [
|
|
343
364
|
never,
|
|
344
365
|
]
|
|
345
|
-
?
|
|
346
|
-
|
|
366
|
+
? [FieldTypeRefOf<FieldState>] extends [never]
|
|
367
|
+
? DescriptorTypeRef<FieldDescriptorOf<FieldState>>
|
|
368
|
+
: ResolveNamedStorageTypeKey<Definition, FieldTypeRefOf<FieldState>>
|
|
369
|
+
: undefined;
|
|
347
370
|
|
|
348
371
|
type ResolveFieldColumnTypeParams<Definition, FieldState> = [
|
|
349
372
|
ResolveFieldColumnTypeRef<Definition, FieldState>,
|
|
@@ -558,6 +581,37 @@ type BuiltStorageTables<Definition> = {
|
|
|
558
581
|
: Record<string, never>);
|
|
559
582
|
};
|
|
560
583
|
|
|
584
|
+
type DefinitionEnums<Definition> = Definition extends {
|
|
585
|
+
readonly enums?: infer E;
|
|
586
|
+
}
|
|
587
|
+
? Present<E> extends Record<string, EnumTypeHandle>
|
|
588
|
+
? // A bare `Record<string, EnumTypeHandle>` (no literal keys) is the
|
|
589
|
+
// widened default for a contract authored without enums; treat it as
|
|
590
|
+
// empty so `db.enums` carries only literally-authored enums.
|
|
591
|
+
string extends keyof Present<E>
|
|
592
|
+
? Record<never, never>
|
|
593
|
+
: Present<E>
|
|
594
|
+
: Record<never, never>
|
|
595
|
+
: Record<never, never>;
|
|
596
|
+
|
|
597
|
+
type EnumHandleAccessorType<Handle> =
|
|
598
|
+
Handle extends EnumTypeHandle<infer _Name, infer Values, infer Names, infer MembersMap>
|
|
599
|
+
? {
|
|
600
|
+
readonly values: Values;
|
|
601
|
+
readonly names: Names;
|
|
602
|
+
readonly members: MembersMap;
|
|
603
|
+
has(v: Values[number]): boolean;
|
|
604
|
+
nameOf(v: Values[number]): string | undefined;
|
|
605
|
+
ordinalOf(v: Values[number]): number;
|
|
606
|
+
}
|
|
607
|
+
: never;
|
|
608
|
+
|
|
609
|
+
type BuiltEnumAccessors<Definition> = {
|
|
610
|
+
readonly [K in keyof DefinitionEnums<Definition>]: EnumHandleAccessorType<
|
|
611
|
+
DefinitionEnums<Definition>[K]
|
|
612
|
+
>;
|
|
613
|
+
};
|
|
614
|
+
|
|
561
615
|
type BuiltDocumentScopedTypes<Definition> = {
|
|
562
616
|
readonly [K in keyof DefinitionTypes<Definition> as DefinitionTypes<Definition>[K] extends StorageTypeInstance
|
|
563
617
|
? K
|
|
@@ -610,29 +664,53 @@ type BuiltStorage<Definition> = {
|
|
|
610
664
|
};
|
|
611
665
|
};
|
|
612
666
|
|
|
613
|
-
|
|
667
|
+
// The enum value union for an enum-typed field, or `never` for a non-enum
|
|
668
|
+
// field. The field's `typeRef` carries the authored `EnumTypeHandle`, whose
|
|
669
|
+
// `Values` tuple preserves the literal member values (text or numeric).
|
|
670
|
+
type EnumValueUnion<FieldState> = [FieldTypeRefOf<FieldState>] extends [
|
|
671
|
+
EnumTypeHandle<string, infer Values>,
|
|
672
|
+
]
|
|
673
|
+
? readonly unknown[] extends Values
|
|
674
|
+
? never
|
|
675
|
+
: Values[number]
|
|
676
|
+
: never;
|
|
677
|
+
|
|
678
|
+
// The codec's `output` / `input` JS type for a field's column, before
|
|
679
|
+
// nullability. `unknown` when the codec is not in the definition's codec map.
|
|
680
|
+
type CodecChannelType<
|
|
614
681
|
Definition,
|
|
615
682
|
ModelName extends ModelNames<Definition>,
|
|
616
683
|
FieldName extends ModelFieldNames<Definition, ModelName>,
|
|
684
|
+
Channel extends 'output' | 'input',
|
|
685
|
+
> = ModelStorageColumn<Definition, ModelName, FieldName>['codecId'] extends infer Id extends
|
|
686
|
+
keyof CodecTypesFromDefinition<Definition>
|
|
687
|
+
? CodecTypesFromDefinition<Definition>[Id] extends { readonly [K in Channel]: infer T }
|
|
688
|
+
? T
|
|
689
|
+
: unknown
|
|
690
|
+
: unknown;
|
|
691
|
+
|
|
692
|
+
// A field's read/write JS type: the enum value union when the field is
|
|
693
|
+
// enum-typed, otherwise the codec channel type, with column nullability applied.
|
|
694
|
+
type FieldChannelType<
|
|
695
|
+
Definition,
|
|
696
|
+
ModelName extends ModelNames<Definition>,
|
|
697
|
+
FieldName extends ModelFieldNames<Definition, ModelName>,
|
|
698
|
+
Channel extends 'output' | 'input',
|
|
617
699
|
> =
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
: unknown
|
|
627
|
-
: unknown
|
|
628
|
-
: unknown;
|
|
629
|
-
|
|
630
|
-
type FieldOutputTypes<Definition> = {
|
|
700
|
+
| ([EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>] extends [never]
|
|
701
|
+
? CodecChannelType<Definition, ModelName, FieldName, Channel>
|
|
702
|
+
: EnumValueUnion<ModelFieldState<Definition, ModelName, FieldName>>)
|
|
703
|
+
| (FieldNullableOf<ModelFieldState<Definition, ModelName, FieldName>> extends true
|
|
704
|
+
? null
|
|
705
|
+
: never);
|
|
706
|
+
|
|
707
|
+
type FieldChannelTypes<Definition, Channel extends 'output' | 'input'> = {
|
|
631
708
|
readonly [ModelName in ModelNames<Definition>]: {
|
|
632
|
-
readonly [FieldName in ModelFieldNames<Definition, ModelName>]:
|
|
709
|
+
readonly [FieldName in ModelFieldNames<Definition, ModelName>]: FieldChannelType<
|
|
633
710
|
Definition,
|
|
634
711
|
ModelName,
|
|
635
|
-
FieldName
|
|
712
|
+
FieldName,
|
|
713
|
+
Channel
|
|
636
714
|
>;
|
|
637
715
|
};
|
|
638
716
|
};
|
|
@@ -646,11 +724,12 @@ export type SqlContractResult<Definition> = ContractWithTypeMaps<
|
|
|
646
724
|
? Record<string, never>
|
|
647
725
|
: DefinitionExtensionPacks<Definition>;
|
|
648
726
|
readonly capabilities: DerivedCapabilities<Definition>;
|
|
727
|
+
readonly enumAccessors: BuiltEnumAccessors<Definition>;
|
|
649
728
|
},
|
|
650
729
|
TypeMaps<
|
|
651
730
|
CodecTypesFromDefinition<Definition>,
|
|
652
731
|
Record<string, never>,
|
|
653
|
-
|
|
654
|
-
|
|
732
|
+
FieldChannelTypes<Definition, 'output'>,
|
|
733
|
+
FieldChannelTypes<Definition, 'input'>
|
|
655
734
|
>
|
|
656
735
|
>;
|