@prisma-next/sql-contract-ts 0.8.0 → 0.9.0-dev.2
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 +27 -9
- package/dist/contract-builder.d.mts +26 -26
- package/dist/contract-builder.d.mts.map +1 -1
- package/dist/contract-builder.mjs +61 -8
- package/dist/contract-builder.mjs.map +1 -1
- package/package.json +10 -10
- package/src/authoring-helper-runtime.ts +8 -3
- package/src/build-contract.ts +30 -3
- package/src/composed-authoring-helpers.ts +91 -37
- package/src/contract-builder.ts +15 -6
- package/src/contract-definition.ts +6 -2
- package/src/contract-dsl.ts +8 -2
- package/src/contract-lowering.ts +24 -12
- package/src/contract-types.ts +12 -3
- package/src/contract-warnings.ts +6 -3
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/sql-contract-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-dev.2",
|
|
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.
|
|
10
|
-
"@prisma-next/contract": "0.
|
|
11
|
-
"@prisma-next/contract-authoring": "0.
|
|
12
|
-
"@prisma-next/framework-components": "0.
|
|
13
|
-
"@prisma-next/sql-contract": "0.
|
|
14
|
-
"@prisma-next/utils": "0.
|
|
9
|
+
"@prisma-next/config": "0.9.0-dev.2",
|
|
10
|
+
"@prisma-next/contract": "0.9.0-dev.2",
|
|
11
|
+
"@prisma-next/contract-authoring": "0.9.0-dev.2",
|
|
12
|
+
"@prisma-next/framework-components": "0.9.0-dev.2",
|
|
13
|
+
"@prisma-next/sql-contract": "0.9.0-dev.2",
|
|
14
|
+
"@prisma-next/utils": "0.9.0-dev.2",
|
|
15
15
|
"arktype": "^2.1.29",
|
|
16
16
|
"pathe": "^2.0.3",
|
|
17
17
|
"ts-toolbelt": "^9.6.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@prisma-next/test-utils": "0.
|
|
21
|
-
"@prisma-next/tsconfig": "0.
|
|
20
|
+
"@prisma-next/test-utils": "0.9.0-dev.2",
|
|
21
|
+
"@prisma-next/tsconfig": "0.9.0-dev.2",
|
|
22
22
|
"@types/pg": "8.20.0",
|
|
23
23
|
"pg": "8.20.0",
|
|
24
|
-
"@prisma-next/tsdown": "0.
|
|
24
|
+
"@prisma-next/tsdown": "0.9.0-dev.2",
|
|
25
25
|
"tsdown": "0.22.0",
|
|
26
26
|
"typescript": "5.9.3",
|
|
27
27
|
"vitest": "4.1.5"
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
isAuthoringTypeConstructorDescriptor,
|
|
10
10
|
validateAuthoringHelperArguments,
|
|
11
11
|
} from '@prisma-next/framework-components/authoring';
|
|
12
|
-
import type
|
|
12
|
+
import { type StorageTypeInstance, toStorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
13
13
|
|
|
14
14
|
export type RuntimeNamedConstraintSpec = {
|
|
15
15
|
readonly name?: string;
|
|
@@ -51,9 +51,14 @@ export function createTypeHelpersFromNamespace(
|
|
|
51
51
|
|
|
52
52
|
if (isAuthoringTypeConstructorDescriptor(value)) {
|
|
53
53
|
const helperPath = currentPath.join('.');
|
|
54
|
-
helpers[key] = (...args: readonly unknown[]) => {
|
|
54
|
+
helpers[key] = (...args: readonly unknown[]): StorageTypeInstance => {
|
|
55
55
|
validateAuthoringHelperArguments(helperPath, value.args, args);
|
|
56
|
-
|
|
56
|
+
const triple = instantiateAuthoringTypeConstructor(value, args);
|
|
57
|
+
return toStorageTypeInstance({
|
|
58
|
+
codecId: triple.codecId,
|
|
59
|
+
nativeType: triple.nativeType,
|
|
60
|
+
typeParams: triple.typeParams ?? {},
|
|
61
|
+
});
|
|
57
62
|
};
|
|
58
63
|
continue;
|
|
59
64
|
}
|
package/src/build-contract.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type StorageHashBase,
|
|
18
18
|
} from '@prisma-next/contract/types';
|
|
19
19
|
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
20
|
+
import { UNSPECIFIED_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
20
21
|
import { validateIndexTypes } from '@prisma-next/sql-contract/index-type-validation';
|
|
21
22
|
import {
|
|
22
23
|
createIndexTypeRegistry,
|
|
@@ -25,10 +26,14 @@ import {
|
|
|
25
26
|
} from '@prisma-next/sql-contract/index-types';
|
|
26
27
|
import {
|
|
27
28
|
applyFkDefaults,
|
|
28
|
-
|
|
29
|
+
isPostgresEnumStorageEntry,
|
|
30
|
+
type PostgresEnumStorageEntry,
|
|
31
|
+
SqlStorage,
|
|
32
|
+
SqlUnspecifiedNamespace,
|
|
29
33
|
type StorageColumn,
|
|
30
34
|
type StorageTable,
|
|
31
35
|
type StorageTypeInstance,
|
|
36
|
+
toStorageTypeInstance,
|
|
32
37
|
} from '@prisma-next/sql-contract/types';
|
|
33
38
|
import { validateStorageSemantics } from '@prisma-next/sql-contract/validators';
|
|
34
39
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
@@ -387,15 +392,37 @@ export function buildSqlContractFromDefinition(
|
|
|
387
392
|
|
|
388
393
|
// --- Assemble contract ---
|
|
389
394
|
|
|
390
|
-
|
|
395
|
+
// Normalise raw codec-triple inputs to the `kind: 'codec-instance'`
|
|
396
|
+
// discriminator shape before hashing so the storageHash matches the
|
|
397
|
+
// persisted JSON envelope produced from the SqlStorage class instance
|
|
398
|
+
// (which always carries the discriminator).
|
|
399
|
+
const rawStorageTypes = (definition.storageTypes ?? {}) as Record<
|
|
400
|
+
string,
|
|
401
|
+
StorageTypeInstance | PostgresEnumStorageEntry
|
|
402
|
+
>;
|
|
403
|
+
const storageTypes = Object.fromEntries(
|
|
404
|
+
Object.entries(rawStorageTypes).map(([name, entry]) => {
|
|
405
|
+
if (isPostgresEnumStorageEntry(entry)) return [name, entry];
|
|
406
|
+
if ((entry as { kind?: unknown }).kind === 'codec-instance') return [name, entry];
|
|
407
|
+
return [
|
|
408
|
+
name,
|
|
409
|
+
toStorageTypeInstance({
|
|
410
|
+
codecId: entry.codecId,
|
|
411
|
+
nativeType: entry.nativeType,
|
|
412
|
+
typeParams: (entry as { typeParams?: Record<string, unknown> }).typeParams ?? {},
|
|
413
|
+
}),
|
|
414
|
+
];
|
|
415
|
+
}),
|
|
416
|
+
);
|
|
391
417
|
const storageWithoutHash = {
|
|
392
418
|
tables: storageTables,
|
|
393
419
|
types: storageTypes,
|
|
420
|
+
namespaces: { [UNSPECIFIED_NAMESPACE_ID]: SqlUnspecifiedNamespace.instance },
|
|
394
421
|
};
|
|
395
422
|
const storageHash: StorageHashBase<string> = definition.storageHash
|
|
396
423
|
? coreHash(definition.storageHash)
|
|
397
424
|
: computeStorageHash({ target, targetFamily, storage: storageWithoutHash });
|
|
398
|
-
const storage
|
|
425
|
+
const storage = new SqlStorage({ ...storageWithoutHash, storageHash });
|
|
399
426
|
|
|
400
427
|
const executionSection =
|
|
401
428
|
executionDefaults.length > 0
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createEntityHelpersFromNamespace,
|
|
3
|
+
type EntityHelpersFromNamespace,
|
|
4
|
+
type ExtractAuthoringNamespaceFromPack,
|
|
5
|
+
type MergeExtensionAuthoringNamespaces,
|
|
6
|
+
} from '@prisma-next/contract-authoring';
|
|
1
7
|
import type {
|
|
2
8
|
AuthoringArgumentDescriptor,
|
|
9
|
+
AuthoringEntityTypeNamespace,
|
|
3
10
|
AuthoringFieldNamespace,
|
|
4
11
|
AuthoringTypeConstructorDescriptor,
|
|
5
12
|
AuthoringTypeNamespace,
|
|
6
13
|
} from '@prisma-next/framework-components/authoring';
|
|
7
14
|
import {
|
|
8
15
|
assertNoCrossRegistryCollisions,
|
|
16
|
+
isAuthoringEntityTypeDescriptor,
|
|
9
17
|
isAuthoringFieldPresetDescriptor,
|
|
10
18
|
isAuthoringTypeConstructorDescriptor,
|
|
11
19
|
mergeAuthoringNamespaces,
|
|
@@ -24,7 +32,6 @@ import type {
|
|
|
24
32
|
FieldHelpersFromNamespace,
|
|
25
33
|
ResolveTemplateValue,
|
|
26
34
|
TupleFromArgumentDescriptors,
|
|
27
|
-
UnionToIntersection,
|
|
28
35
|
} from './authoring-type-utils';
|
|
29
36
|
import type {
|
|
30
37
|
AnyRelationBuilder,
|
|
@@ -35,44 +42,40 @@ import type {
|
|
|
35
42
|
import { buildFieldPreset, field, model, rel } from './contract-dsl';
|
|
36
43
|
import type { MergeExtensionIndexTypes } from './contract-types';
|
|
37
44
|
|
|
38
|
-
type ExtractTypeNamespaceFromPack<Pack> =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
type ExtractTypeNamespaceFromPack<Pack> = ExtractAuthoringNamespaceFromPack<
|
|
46
|
+
Pack,
|
|
47
|
+
'type',
|
|
48
|
+
Record<never, never>
|
|
49
|
+
>;
|
|
50
|
+
type ExtractFieldNamespaceFromPack<Pack> = ExtractAuthoringNamespaceFromPack<
|
|
51
|
+
Pack,
|
|
52
|
+
'field',
|
|
53
|
+
Record<never, never>
|
|
54
|
+
>;
|
|
55
|
+
type ExtractEntitiesNamespaceFromPack<Pack> = ExtractAuthoringNamespaceFromPack<
|
|
56
|
+
Pack,
|
|
57
|
+
'entityTypes',
|
|
58
|
+
Record<never, never>
|
|
59
|
+
>;
|
|
43
60
|
|
|
44
|
-
type
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
[K in keyof ExtensionPacks]: ExtractTypeNamespaceFromPack<ExtensionPacks[K]>;
|
|
57
|
-
}[keyof ExtensionPacks]
|
|
58
|
-
>
|
|
59
|
-
: Record<never, never>;
|
|
60
|
-
|
|
61
|
-
type MergeExtensionFieldNamespaces<ExtensionPacks> =
|
|
62
|
-
ExtensionPacks extends Record<string, unknown>
|
|
63
|
-
? keyof ExtensionPacks extends never
|
|
64
|
-
? Record<never, never>
|
|
65
|
-
: UnionToIntersection<
|
|
66
|
-
{
|
|
67
|
-
[K in keyof ExtensionPacks]: ExtractFieldNamespaceFromPack<ExtensionPacks[K]>;
|
|
68
|
-
}[keyof ExtensionPacks]
|
|
69
|
-
>
|
|
70
|
-
: Record<never, never>;
|
|
61
|
+
type MergeExtensionTypeNamespaces<ExtensionPacks> = MergeExtensionAuthoringNamespaces<
|
|
62
|
+
ExtensionPacks,
|
|
63
|
+
'type'
|
|
64
|
+
>;
|
|
65
|
+
type MergeExtensionFieldNamespaces<ExtensionPacks> = MergeExtensionAuthoringNamespaces<
|
|
66
|
+
ExtensionPacks,
|
|
67
|
+
'field'
|
|
68
|
+
>;
|
|
69
|
+
type MergeExtensionEntityNamespaces<ExtensionPacks> = MergeExtensionAuthoringNamespaces<
|
|
70
|
+
ExtensionPacks,
|
|
71
|
+
'entityTypes'
|
|
72
|
+
>;
|
|
71
73
|
|
|
72
74
|
type StorageTypeFromDescriptor<
|
|
73
75
|
Descriptor extends AuthoringTypeConstructorDescriptor,
|
|
74
76
|
Args extends readonly unknown[],
|
|
75
77
|
> = {
|
|
78
|
+
readonly kind: 'codec-instance';
|
|
76
79
|
readonly codecId: ResolveTemplateValue<Descriptor['output']['codecId'], Args>;
|
|
77
80
|
readonly nativeType: ResolveTemplateValue<Descriptor['output']['nativeType'], Args>;
|
|
78
81
|
} & (Descriptor['output'] extends {
|
|
@@ -81,7 +84,7 @@ type StorageTypeFromDescriptor<
|
|
|
81
84
|
? {
|
|
82
85
|
readonly typeParams: ResolveTemplateValue<TypeParams, Args>;
|
|
83
86
|
}
|
|
84
|
-
: Record<never, never>);
|
|
87
|
+
: { readonly typeParams: Record<never, never> });
|
|
85
88
|
|
|
86
89
|
type TypeHelperFunction<Descriptor extends AuthoringTypeConstructorDescriptor> =
|
|
87
90
|
Descriptor extends { readonly args: infer Args extends readonly AuthoringArgumentDescriptor[] }
|
|
@@ -131,7 +134,11 @@ export type ComposedAuthoringHelpers<
|
|
|
131
134
|
Family extends FamilyPackRef<string>,
|
|
132
135
|
Target extends TargetPackRef<'sql', string>,
|
|
133
136
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
134
|
-
> =
|
|
137
|
+
> = EntityHelpersFromNamespace<
|
|
138
|
+
ExtractEntitiesNamespaceFromPack<Family> &
|
|
139
|
+
ExtractEntitiesNamespaceFromPack<Target> &
|
|
140
|
+
MergeExtensionEntityNamespaces<ExtensionPacks>
|
|
141
|
+
> & {
|
|
135
142
|
readonly field: CoreFieldHelpers &
|
|
136
143
|
FieldHelpersFromNamespace<
|
|
137
144
|
ExtractFieldNamespaceFromPack<Family> &
|
|
@@ -157,8 +164,17 @@ function extractFieldNamespace<Pack>(pack: Pack): ExtractFieldNamespaceFromPack<
|
|
|
157
164
|
{}) as ExtractFieldNamespaceFromPack<Pack>;
|
|
158
165
|
}
|
|
159
166
|
|
|
167
|
+
function extractEntitiesNamespace<Pack>(pack: Pack): ExtractEntitiesNamespaceFromPack<Pack> {
|
|
168
|
+
return ((pack as { readonly authoring?: { readonly entityTypes?: unknown } }).authoring
|
|
169
|
+
?.entityTypes ?? {}) as ExtractEntitiesNamespaceFromPack<Pack>;
|
|
170
|
+
}
|
|
171
|
+
|
|
160
172
|
type AuthoringComponent = {
|
|
161
|
-
readonly authoring?: {
|
|
173
|
+
readonly authoring?: {
|
|
174
|
+
readonly type?: unknown;
|
|
175
|
+
readonly field?: unknown;
|
|
176
|
+
readonly entityTypes?: unknown;
|
|
177
|
+
};
|
|
162
178
|
};
|
|
163
179
|
|
|
164
180
|
function composeTypeNamespace(components: readonly AuthoringComponent[]): AuthoringTypeNamespace {
|
|
@@ -183,6 +199,39 @@ function composeFieldNamespace(components: readonly AuthoringComponent[]): Autho
|
|
|
183
199
|
return merged as AuthoringFieldNamespace;
|
|
184
200
|
}
|
|
185
201
|
|
|
202
|
+
function composeEntityNamespace(
|
|
203
|
+
components: readonly AuthoringComponent[],
|
|
204
|
+
): AuthoringEntityTypeNamespace {
|
|
205
|
+
const merged: Record<string, unknown> = {};
|
|
206
|
+
for (const component of components) {
|
|
207
|
+
const ns = extractEntitiesNamespace(component);
|
|
208
|
+
if (Object.keys(ns).length > 0) {
|
|
209
|
+
mergeAuthoringNamespaces(merged, ns, [], isAuthoringEntityTypeDescriptor, 'entity');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return merged as AuthoringEntityTypeNamespace;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Reserved top-level keys on the composed helpers surface — the
|
|
217
|
+
* built-in `model` / `rel` helpers, the `field` / `type` namespace
|
|
218
|
+
* objects. Pack-contributed entity types are flattened to the same
|
|
219
|
+
* top-level shape (e.g. `helpers.enum({...})`), so a pack cannot
|
|
220
|
+
* contribute an entity type whose name collides with one of these
|
|
221
|
+
* reserved keys without silently overwriting at runtime. Detect the
|
|
222
|
+
* collision at compose time and fail loudly with a guidance message.
|
|
223
|
+
*/
|
|
224
|
+
const RESERVED_HELPER_KEYS: readonly string[] = ['field', 'model', 'rel', 'type'];
|
|
225
|
+
|
|
226
|
+
function assertNoBuiltInEntityCollisions(namespace: AuthoringEntityTypeNamespace): void {
|
|
227
|
+
const collisions = Object.keys(namespace).filter((name) => RESERVED_HELPER_KEYS.includes(name));
|
|
228
|
+
if (collisions.length > 0) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
`Pack-contributed entity type(s) ${collisions.map((c) => `"${c}"`).join(', ')} collide with the reserved built-in helper key(s) on the composed helpers surface. Reserved keys: ${RESERVED_HELPER_KEYS.map((k) => `"${k}"`).join(', ')}.`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
186
235
|
function createComposedFieldHelpers(
|
|
187
236
|
fieldNamespace: AuthoringFieldNamespace,
|
|
188
237
|
): CoreFieldHelpers & Record<string, unknown> {
|
|
@@ -237,11 +286,16 @@ export function createComposedAuthoringHelpers<
|
|
|
237
286
|
|
|
238
287
|
const typeNamespace = composeTypeNamespace(components);
|
|
239
288
|
const fieldNamespace = composeFieldNamespace(components);
|
|
289
|
+
const entityNamespace = composeEntityNamespace(components);
|
|
240
290
|
// Mirrors the call in `assembleAuthoringContributions`: PSL composes via
|
|
241
291
|
// `createControlStack`, the TS DSL composes here. Both seams need the guard.
|
|
242
|
-
assertNoCrossRegistryCollisions(typeNamespace, fieldNamespace);
|
|
292
|
+
assertNoCrossRegistryCollisions(typeNamespace, fieldNamespace, entityNamespace);
|
|
293
|
+
assertNoBuiltInEntityCollisions(entityNamespace);
|
|
243
294
|
|
|
244
295
|
return {
|
|
296
|
+
...createEntityHelpersFromNamespace(entityNamespace, {
|
|
297
|
+
ctx: { family: options.family.familyId, target: options.target.targetId },
|
|
298
|
+
}),
|
|
245
299
|
field: createComposedFieldHelpers(fieldNamespace),
|
|
246
300
|
model,
|
|
247
301
|
rel,
|
package/src/contract-builder.ts
CHANGED
|
@@ -5,7 +5,10 @@ import type {
|
|
|
5
5
|
FamilyPackRef,
|
|
6
6
|
TargetPackRef,
|
|
7
7
|
} from '@prisma-next/framework-components/components';
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
PostgresEnumStorageEntry,
|
|
10
|
+
StorageTypeInstance,
|
|
11
|
+
} from '@prisma-next/sql-contract/types';
|
|
9
12
|
import { buildSqlContractFromDefinition } from './build-contract';
|
|
10
13
|
import {
|
|
11
14
|
type ComposedAuthoringHelpers,
|
|
@@ -44,7 +47,7 @@ type ModelLike = {
|
|
|
44
47
|
type ContractDefinition<
|
|
45
48
|
Family extends FamilyPackRef<string>,
|
|
46
49
|
Target extends TargetPackRef<'sql', string>,
|
|
47
|
-
Types extends Record<string, StorageTypeInstance>,
|
|
50
|
+
Types extends Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
48
51
|
Models extends Record<string, ModelLike>,
|
|
49
52
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
50
53
|
Capabilities extends Record<string, Record<string, boolean>> | undefined,
|
|
@@ -86,7 +89,7 @@ type ContractScaffold<
|
|
|
86
89
|
type ContractFactory<
|
|
87
90
|
Family extends FamilyPackRef<string>,
|
|
88
91
|
Target extends TargetPackRef<'sql', string>,
|
|
89
|
-
Types extends Record<string, StorageTypeInstance>,
|
|
92
|
+
Types extends Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
90
93
|
Models extends Record<string, ModelLike>,
|
|
91
94
|
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
92
95
|
> = (helpers: ComposedAuthoringHelpers<Family, Target, ExtensionPacks>) => {
|
|
@@ -159,7 +162,10 @@ function buildContractFromDsl(
|
|
|
159
162
|
export function defineContract<
|
|
160
163
|
const Family extends FamilyPackRef<string>,
|
|
161
164
|
const Target extends TargetPackRef<'sql', string>,
|
|
162
|
-
const Types extends Record<string, StorageTypeInstance> = Record<
|
|
165
|
+
const Types extends Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = Record<
|
|
166
|
+
never,
|
|
167
|
+
never
|
|
168
|
+
>,
|
|
163
169
|
const Models extends Record<string, ModelLike> = Record<never, never>,
|
|
164
170
|
const ExtensionPacks extends
|
|
165
171
|
| Record<string, ExtensionPackRef<'sql', string>>
|
|
@@ -196,7 +202,10 @@ export function defineContract<
|
|
|
196
202
|
export function defineContract<
|
|
197
203
|
const Family extends FamilyPackRef<string>,
|
|
198
204
|
const Target extends TargetPackRef<'sql', string>,
|
|
199
|
-
const Types extends Record<string, StorageTypeInstance> = Record<
|
|
205
|
+
const Types extends Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = Record<
|
|
206
|
+
never,
|
|
207
|
+
never
|
|
208
|
+
>,
|
|
200
209
|
const Models extends Record<string, ModelLike> = Record<never, never>,
|
|
201
210
|
const ExtensionPacks extends
|
|
202
211
|
| Record<string, ExtensionPackRef<'sql', string>>
|
|
@@ -234,7 +243,7 @@ export function defineContract(
|
|
|
234
243
|
factory?: ContractFactory<
|
|
235
244
|
FamilyPackRef<string>,
|
|
236
245
|
TargetPackRef<'sql', string>,
|
|
237
|
-
Record<string, StorageTypeInstance>,
|
|
246
|
+
Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
238
247
|
Record<string, ModelLike>,
|
|
239
248
|
Record<string, ExtensionPackRef<'sql', string>> | undefined
|
|
240
249
|
>,
|
|
@@ -2,7 +2,11 @@ import type { ColumnDefault, ExecutionMutationDefaultPhases } from '@prisma-next
|
|
|
2
2
|
import type { ForeignKeyDefaultsState } from '@prisma-next/contract-authoring';
|
|
3
3
|
import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/codec';
|
|
4
4
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
PostgresEnumStorageEntry,
|
|
7
|
+
ReferentialAction,
|
|
8
|
+
StorageTypeInstance,
|
|
9
|
+
} from '@prisma-next/sql-contract/types';
|
|
6
10
|
|
|
7
11
|
export type { ExecutionMutationDefaultPhases };
|
|
8
12
|
|
|
@@ -97,7 +101,7 @@ export interface ContractDefinition {
|
|
|
97
101
|
readonly capabilities?: Record<string, Record<string, boolean>>;
|
|
98
102
|
readonly storageHash?: string;
|
|
99
103
|
readonly foreignKeyDefaults?: ForeignKeyDefaultsState;
|
|
100
|
-
readonly storageTypes?: Record<string, StorageTypeInstance>;
|
|
104
|
+
readonly storageTypes?: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>;
|
|
101
105
|
readonly models: readonly ModelNode[];
|
|
102
106
|
readonly valueObjects?: readonly ValueObjectNode[];
|
|
103
107
|
}
|
package/src/contract-dsl.ts
CHANGED
|
@@ -14,7 +14,10 @@ import type {
|
|
|
14
14
|
FamilyPackRef,
|
|
15
15
|
TargetPackRef,
|
|
16
16
|
} from '@prisma-next/framework-components/components';
|
|
17
|
-
import type {
|
|
17
|
+
import type {
|
|
18
|
+
PostgresEnumStorageEntry,
|
|
19
|
+
StorageTypeInstance,
|
|
20
|
+
} from '@prisma-next/sql-contract/types';
|
|
18
21
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
19
22
|
import type { NamedConstraintSpec } from './authoring-type-utils';
|
|
20
23
|
|
|
@@ -25,7 +28,7 @@ export type NamingConfig = {
|
|
|
25
28
|
readonly columns?: NamingStrategy;
|
|
26
29
|
};
|
|
27
30
|
|
|
28
|
-
type NamedStorageTypeRef = string | StorageTypeInstance;
|
|
31
|
+
type NamedStorageTypeRef = string | StorageTypeInstance | PostgresEnumStorageEntry;
|
|
29
32
|
|
|
30
33
|
type NamedConstraintNameSpec<Name extends string = string> = {
|
|
31
34
|
readonly name: Name;
|
|
@@ -349,6 +352,9 @@ function namedTypeField<TypeRef extends string>(
|
|
|
349
352
|
function namedTypeField<TypeRef extends StorageTypeInstance>(
|
|
350
353
|
typeRef: TypeRef,
|
|
351
354
|
): ScalarFieldBuilder<ScalarFieldState<TypeRef['codecId'], TypeRef, false, undefined>>;
|
|
355
|
+
function namedTypeField<TypeRef extends PostgresEnumStorageEntry>(
|
|
356
|
+
typeRef: TypeRef,
|
|
357
|
+
): ScalarFieldBuilder<ScalarFieldState<string, TypeRef, false, undefined>>;
|
|
352
358
|
function namedTypeField(
|
|
353
359
|
typeRef: NamedStorageTypeRef,
|
|
354
360
|
): ScalarFieldBuilder<ScalarFieldState<string, NamedStorageTypeRef, false, undefined>> {
|
package/src/contract-lowering.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/codec';
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
isPostgresEnumStorageEntry,
|
|
4
|
+
type PostgresEnumStorageEntry,
|
|
5
|
+
type StorageTypeInstance,
|
|
6
|
+
} from '@prisma-next/sql-contract/types';
|
|
3
7
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
4
8
|
import type {
|
|
5
9
|
ContractDefinition,
|
|
@@ -52,15 +56,15 @@ type RuntimeModelSpec = {
|
|
|
52
56
|
};
|
|
53
57
|
|
|
54
58
|
type RuntimeCollection = {
|
|
55
|
-
readonly storageTypes: Record<string, StorageTypeInstance>;
|
|
59
|
+
readonly storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>;
|
|
56
60
|
readonly models: Record<string, RuntimeModel>;
|
|
57
61
|
readonly modelSpecs: ReadonlyMap<string, RuntimeModelSpec>;
|
|
58
62
|
};
|
|
59
63
|
|
|
60
64
|
function buildStorageTypeReverseLookup(
|
|
61
|
-
storageTypes: Record<string, StorageTypeInstance>,
|
|
62
|
-
): ReadonlyMap<StorageTypeInstance, string> {
|
|
63
|
-
const lookup = new Map<StorageTypeInstance, string>();
|
|
65
|
+
storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
66
|
+
): ReadonlyMap<StorageTypeInstance | PostgresEnumStorageEntry, string> {
|
|
67
|
+
const lookup = new Map<StorageTypeInstance | PostgresEnumStorageEntry, string>();
|
|
64
68
|
for (const [key, instance] of Object.entries(storageTypes)) {
|
|
65
69
|
lookup.set(instance, key);
|
|
66
70
|
}
|
|
@@ -71,8 +75,8 @@ function resolveFieldDescriptor(
|
|
|
71
75
|
modelName: string,
|
|
72
76
|
fieldName: string,
|
|
73
77
|
fieldState: FieldStateOf<ScalarFieldBuilder>,
|
|
74
|
-
storageTypes: Record<string, StorageTypeInstance>,
|
|
75
|
-
storageTypeReverseLookup: ReadonlyMap<StorageTypeInstance, string>,
|
|
78
|
+
storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
79
|
+
storageTypeReverseLookup: ReadonlyMap<StorageTypeInstance | PostgresEnumStorageEntry, string>,
|
|
76
80
|
): ColumnTypeDescriptor {
|
|
77
81
|
if ('descriptor' in fieldState && fieldState.descriptor) {
|
|
78
82
|
return fieldState.descriptor;
|
|
@@ -82,7 +86,9 @@ function resolveFieldDescriptor(
|
|
|
82
86
|
const typeRef =
|
|
83
87
|
typeof fieldState.typeRef === 'string'
|
|
84
88
|
? fieldState.typeRef
|
|
85
|
-
: storageTypeReverseLookup.get(
|
|
89
|
+
: storageTypeReverseLookup.get(
|
|
90
|
+
fieldState.typeRef as StorageTypeInstance | PostgresEnumStorageEntry,
|
|
91
|
+
);
|
|
86
92
|
|
|
87
93
|
if (!typeRef) {
|
|
88
94
|
throw new Error(
|
|
@@ -97,8 +103,11 @@ function resolveFieldDescriptor(
|
|
|
97
103
|
);
|
|
98
104
|
}
|
|
99
105
|
|
|
106
|
+
const codecId = isPostgresEnumStorageEntry(referencedType)
|
|
107
|
+
? referencedType.codecId
|
|
108
|
+
: referencedType.codecId;
|
|
100
109
|
return {
|
|
101
|
-
codecId
|
|
110
|
+
codecId,
|
|
102
111
|
nativeType: referencedType.nativeType,
|
|
103
112
|
typeRef,
|
|
104
113
|
};
|
|
@@ -538,8 +547,8 @@ function resolveForeignKeyNodes(
|
|
|
538
547
|
function resolveModelNode(
|
|
539
548
|
spec: RuntimeModelSpec,
|
|
540
549
|
allSpecs: ReadonlyMap<string, RuntimeModelSpec>,
|
|
541
|
-
storageTypes: Record<string, StorageTypeInstance>,
|
|
542
|
-
storageTypeReverseLookup: ReadonlyMap<StorageTypeInstance, string>,
|
|
550
|
+
storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
551
|
+
storageTypeReverseLookup: ReadonlyMap<StorageTypeInstance | PostgresEnumStorageEntry, string>,
|
|
543
552
|
): ModelNode {
|
|
544
553
|
const fields: FieldNode[] = [];
|
|
545
554
|
|
|
@@ -607,7 +616,10 @@ function resolveModelNode(
|
|
|
607
616
|
}
|
|
608
617
|
|
|
609
618
|
function collectRuntimeModelSpecs(definition: ContractInput): RuntimeCollection {
|
|
610
|
-
const storageTypes = { ...(definition.types ?? {}) } as Record<
|
|
619
|
+
const storageTypes = { ...(definition.types ?? {}) } as Record<
|
|
620
|
+
string,
|
|
621
|
+
StorageTypeInstance | PostgresEnumStorageEntry
|
|
622
|
+
>;
|
|
611
623
|
const models = { ...(definition.models ?? {}) } as Record<string, RuntimeModel>;
|
|
612
624
|
|
|
613
625
|
emitTypedNamedTypeFallbackWarnings(models, storageTypes);
|
package/src/contract-types.ts
CHANGED
|
@@ -5,10 +5,12 @@ import type {
|
|
|
5
5
|
StorageHashBase,
|
|
6
6
|
} from '@prisma-next/contract/types';
|
|
7
7
|
import type { ExtensionPackRef, TargetPackRef } from '@prisma-next/framework-components/components';
|
|
8
|
+
import type { Namespace } from '@prisma-next/framework-components/ir';
|
|
8
9
|
import type { IndexTypeRegistration } from '@prisma-next/sql-contract/index-types';
|
|
9
10
|
import type {
|
|
10
11
|
ContractWithTypeMaps,
|
|
11
12
|
Index,
|
|
13
|
+
PostgresEnumStorageEntry,
|
|
12
14
|
ReferentialAction,
|
|
13
15
|
StorageTypeInstance,
|
|
14
16
|
TypeMaps,
|
|
@@ -108,7 +110,10 @@ type DefinitionModels<Definition> = Definition extends {
|
|
|
108
110
|
type DefinitionTypes<Definition> = Definition extends {
|
|
109
111
|
readonly types?: unknown;
|
|
110
112
|
}
|
|
111
|
-
? Present<Definition['types']> extends Record<
|
|
113
|
+
? Present<Definition['types']> extends Record<
|
|
114
|
+
string,
|
|
115
|
+
StorageTypeInstance | PostgresEnumStorageEntry
|
|
116
|
+
>
|
|
112
117
|
? Present<Definition['types']>
|
|
113
118
|
: Record<never, never>
|
|
114
119
|
: Record<never, never>;
|
|
@@ -272,7 +277,10 @@ type DescriptorTypeRef<Descriptor> = Descriptor extends {
|
|
|
272
277
|
? TypeRef
|
|
273
278
|
: undefined;
|
|
274
279
|
|
|
275
|
-
type LookupNamedStorageTypeKeyByValue<
|
|
280
|
+
type LookupNamedStorageTypeKeyByValue<
|
|
281
|
+
Definition,
|
|
282
|
+
TypeRef extends StorageTypeInstance | PostgresEnumStorageEntry,
|
|
283
|
+
> = {
|
|
276
284
|
[TypeName in keyof DefinitionTypes<Definition> & string]: [TypeRef] extends [
|
|
277
285
|
DefinitionTypes<Definition>[TypeName],
|
|
278
286
|
]
|
|
@@ -284,7 +292,7 @@ type LookupNamedStorageTypeKeyByValue<Definition, TypeRef extends StorageTypeIns
|
|
|
284
292
|
|
|
285
293
|
type ResolveNamedStorageTypeKey<Definition, TypeRef> = TypeRef extends string
|
|
286
294
|
? TypeRef
|
|
287
|
-
: TypeRef extends StorageTypeInstance
|
|
295
|
+
: TypeRef extends StorageTypeInstance | PostgresEnumStorageEntry
|
|
288
296
|
? [LookupNamedStorageTypeKeyByValue<Definition, TypeRef>] extends [never]
|
|
289
297
|
? string
|
|
290
298
|
: LookupNamedStorageTypeKeyByValue<Definition, TypeRef>
|
|
@@ -517,6 +525,7 @@ type BuiltStorage<Definition> = {
|
|
|
517
525
|
readonly storageHash: StorageHashBase<string>;
|
|
518
526
|
readonly tables: BuiltStorageTables<Definition>;
|
|
519
527
|
readonly types: DefinitionTypes<Definition>;
|
|
528
|
+
readonly namespaces: Readonly<Record<string, Namespace>>;
|
|
520
529
|
};
|
|
521
530
|
|
|
522
531
|
type FieldOutputType<
|
package/src/contract-warnings.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
PostgresEnumStorageEntry,
|
|
3
|
+
StorageTypeInstance,
|
|
4
|
+
} from '@prisma-next/sql-contract/types';
|
|
2
5
|
import {
|
|
3
6
|
type ContractModelBuilder,
|
|
4
7
|
type ModelAttributesSpec,
|
|
@@ -25,7 +28,7 @@ type RuntimeModelSpec = {
|
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
type RuntimeCollection = {
|
|
28
|
-
readonly storageTypes: Record<string, StorageTypeInstance>;
|
|
31
|
+
readonly storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>;
|
|
29
32
|
readonly models: Record<string, RuntimeModel>;
|
|
30
33
|
readonly modelSpecs: ReadonlyMap<string, RuntimeModelSpec>;
|
|
31
34
|
};
|
|
@@ -133,7 +136,7 @@ function formatFallbackWarning(location: string, current: string, suggested: str
|
|
|
133
136
|
|
|
134
137
|
export function emitTypedNamedTypeFallbackWarnings(
|
|
135
138
|
models: Record<string, RuntimeModel>,
|
|
136
|
-
storageTypes: Record<string, StorageTypeInstance>,
|
|
139
|
+
storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry>,
|
|
137
140
|
): void {
|
|
138
141
|
const warnings: string[] = [];
|
|
139
142
|
const warnedFields = new Set<string>();
|