@prisma-next/sql-contract-ts 0.8.0 → 0.9.0-dev.1

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/package.json CHANGED
@@ -1,27 +1,27 @@
1
1
  {
2
2
  "name": "@prisma-next/sql-contract-ts",
3
- "version": "0.8.0",
3
+ "version": "0.9.0-dev.1",
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.8.0",
10
- "@prisma-next/contract": "0.8.0",
11
- "@prisma-next/contract-authoring": "0.8.0",
12
- "@prisma-next/framework-components": "0.8.0",
13
- "@prisma-next/sql-contract": "0.8.0",
14
- "@prisma-next/utils": "0.8.0",
9
+ "@prisma-next/config": "0.9.0-dev.1",
10
+ "@prisma-next/contract": "0.9.0-dev.1",
11
+ "@prisma-next/contract-authoring": "0.9.0-dev.1",
12
+ "@prisma-next/framework-components": "0.9.0-dev.1",
13
+ "@prisma-next/sql-contract": "0.9.0-dev.1",
14
+ "@prisma-next/utils": "0.9.0-dev.1",
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.8.0",
21
- "@prisma-next/tsconfig": "0.8.0",
20
+ "@prisma-next/test-utils": "0.9.0-dev.1",
21
+ "@prisma-next/tsconfig": "0.9.0-dev.1",
22
22
  "@types/pg": "8.20.0",
23
23
  "pg": "8.20.0",
24
- "@prisma-next/tsdown": "0.8.0",
24
+ "@prisma-next/tsdown": "0.9.0-dev.1",
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 { StorageTypeInstance } from '@prisma-next/sql-contract/types';
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
- return instantiateAuthoringTypeConstructor(value, args) as StorageTypeInstance;
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
  }
@@ -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
- type SqlStorage,
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
- const storageTypes = (definition.storageTypes ?? {}) as Record<string, StorageTypeInstance>;
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: SqlStorage = { ...storageWithoutHash, storageHash };
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> = Pack extends {
39
- readonly authoring?: { readonly type?: infer Namespace extends AuthoringTypeNamespace };
40
- }
41
- ? Namespace
42
- : Record<never, never>;
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 ExtractFieldNamespaceFromPack<Pack> = Pack extends {
45
- readonly authoring?: { readonly field?: infer Namespace extends AuthoringFieldNamespace };
46
- }
47
- ? Namespace
48
- : Record<never, never>;
49
-
50
- type MergeExtensionTypeNamespaces<ExtensionPacks> =
51
- ExtensionPacks extends Record<string, unknown>
52
- ? keyof ExtensionPacks extends never
53
- ? Record<never, never>
54
- : UnionToIntersection<
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?: { readonly type?: unknown; readonly field?: unknown };
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,
@@ -5,7 +5,10 @@ import type {
5
5
  FamilyPackRef,
6
6
  TargetPackRef,
7
7
  } from '@prisma-next/framework-components/components';
8
- import type { StorageTypeInstance } from '@prisma-next/sql-contract/types';
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<never, never>,
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<never, never>,
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 { ReferentialAction, StorageTypeInstance } from '@prisma-next/sql-contract/types';
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
  }
@@ -14,7 +14,10 @@ import type {
14
14
  FamilyPackRef,
15
15
  TargetPackRef,
16
16
  } from '@prisma-next/framework-components/components';
17
- import type { StorageTypeInstance } from '@prisma-next/sql-contract/types';
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>> {
@@ -1,5 +1,9 @@
1
1
  import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/codec';
2
- import type { StorageTypeInstance } from '@prisma-next/sql-contract/types';
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(fieldState.typeRef as StorageTypeInstance);
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: referencedType.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<string, StorageTypeInstance>;
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);
@@ -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<string, StorageTypeInstance>
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<Definition, TypeRef extends StorageTypeInstance> = {
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<
@@ -1,4 +1,7 @@
1
- import type { StorageTypeInstance } from '@prisma-next/sql-contract/types';
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>();