@prisma-next/target-postgres 0.13.0-dev.25 → 0.13.0-dev.27

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.
Files changed (53) hide show
  1. package/dist/control.mjs +4 -4
  2. package/dist/{descriptor-meta-26XbSdrs.mjs → descriptor-meta-C7O6XHfh.mjs} +2 -2
  3. package/dist/{descriptor-meta-26XbSdrs.mjs.map → descriptor-meta-C7O6XHfh.mjs.map} +1 -1
  4. package/dist/{descriptor-meta-runtime-B5ZtrgVF.mjs → descriptor-meta-runtime-BToWdas9.mjs} +2 -2
  5. package/dist/descriptor-meta-runtime-BToWdas9.mjs.map +1 -0
  6. package/dist/{enum-planning-eI1gxdKF.mjs → enum-planning-D8z4FH7y.mjs} +2 -2
  7. package/dist/{enum-planning-eI1gxdKF.mjs.map → enum-planning-D8z4FH7y.mjs.map} +1 -1
  8. package/dist/enum-planning.mjs +1 -1
  9. package/dist/{issue-planner-BcVsU7Hh.mjs → issue-planner-CK-XWGB0.mjs} +19 -19
  10. package/dist/issue-planner-CK-XWGB0.mjs.map +1 -0
  11. package/dist/issue-planner.mjs +1 -1
  12. package/dist/migration.mjs +2 -2
  13. package/dist/{op-factory-call-CQQwTUTj.mjs → op-factory-call-CHvtj70z.mjs} +2 -2
  14. package/dist/{op-factory-call-CQQwTUTj.mjs.map → op-factory-call-CHvtj70z.mjs.map} +1 -1
  15. package/dist/op-factory-call.mjs +1 -1
  16. package/dist/pack.mjs +1 -1
  17. package/dist/{planner-B_o3sWWt.mjs → planner-4FbY_95H.mjs} +24 -12
  18. package/dist/planner-4FbY_95H.mjs.map +1 -0
  19. package/dist/{planner-produced-postgres-migration-UBDGd5v_.mjs → planner-produced-postgres-migration-qfkCkGVe.mjs} +2 -2
  20. package/dist/{planner-produced-postgres-migration-UBDGd5v_.mjs.map → planner-produced-postgres-migration-qfkCkGVe.mjs.map} +1 -1
  21. package/dist/planner-produced-postgres-migration.mjs +1 -1
  22. package/dist/{planner-sql-checks-CrAbk7gX.mjs → planner-sql-checks-BLgdXLsA.mjs} +2 -2
  23. package/dist/{planner-sql-checks-CrAbk7gX.mjs.map → planner-sql-checks-BLgdXLsA.mjs.map} +1 -1
  24. package/dist/planner-sql-checks.mjs +1 -1
  25. package/dist/planner.mjs +1 -1
  26. package/dist/{postgres-contract-serializer-BDbqgeFb.mjs → postgres-contract-serializer-CTxVcCVW.mjs} +38 -38
  27. package/dist/postgres-contract-serializer-CTxVcCVW.mjs.map +1 -0
  28. package/dist/postgres-enum-type-schema-DZBTtvBF.mjs +20 -0
  29. package/dist/postgres-enum-type-schema-DZBTtvBF.mjs.map +1 -0
  30. package/dist/{postgres-migration-BQ62jZR_.mjs → postgres-migration-DF5ApLqQ.mjs} +2 -2
  31. package/dist/{postgres-migration-BQ62jZR_.mjs.map → postgres-migration-DF5ApLqQ.mjs.map} +1 -1
  32. package/dist/{postgres-schema-BAgkIU9u.mjs → postgres-schema-C7c9rhGk.mjs} +36 -16
  33. package/dist/postgres-schema-C7c9rhGk.mjs.map +1 -0
  34. package/dist/runtime.d.mts +2 -0
  35. package/dist/runtime.d.mts.map +1 -1
  36. package/dist/runtime.mjs +2 -2
  37. package/dist/types.d.mts +26 -13
  38. package/dist/types.d.mts.map +1 -1
  39. package/dist/types.mjs +3 -2
  40. package/package.json +17 -17
  41. package/src/core/authoring.ts +1 -1
  42. package/src/core/migrations/control-policy.ts +19 -7
  43. package/src/core/migrations/issue-planner.ts +1 -1
  44. package/src/core/migrations/planner-strategies.ts +8 -11
  45. package/src/core/postgres-contract-serializer.ts +75 -53
  46. package/src/core/postgres-enum-type-schema.ts +17 -0
  47. package/src/core/postgres-schema.ts +80 -46
  48. package/src/exports/types.ts +1 -0
  49. package/dist/descriptor-meta-runtime-B5ZtrgVF.mjs.map +0 -1
  50. package/dist/issue-planner-BcVsU7Hh.mjs.map +0 -1
  51. package/dist/planner-B_o3sWWt.mjs.map +0 -1
  52. package/dist/postgres-contract-serializer-BDbqgeFb.mjs.map +0 -1
  53. package/dist/postgres-schema-BAgkIU9u.mjs.map +0 -1
package/dist/types.d.mts CHANGED
@@ -1,16 +1,30 @@
1
1
  import { n as PostgresEnumTypeInput, t as PostgresEnumType } from "./postgres-enum-type-BVn63a89.mjs";
2
2
  import { t as PostgresColumnDefault } from "./types-BDKkx8MA.mjs";
3
3
  import { NamespaceBase } from "@prisma-next/framework-components/ir";
4
- import { PostgresEnumStorageEntry, SqlNamespaceTablesInput, SqlStorage, StorageTable, StorageTableInput, StorageValueSet, StorageValueSetInput } from "@prisma-next/sql-contract/types";
4
+ import { PostgresEnumStorageEntry, SqlNamespaceEntries, SqlNamespaceTablesInput, SqlStorage, StorageTable, StorageValueSet } from "@prisma-next/sql-contract/types";
5
5
 
6
+ //#region src/core/postgres-enum-type-schema.d.ts
7
+ /**
8
+ * Arktype validator for a `postgres-enum` entry under
9
+ * `storage.namespaces[id].entries.type[name]`. Registered by the Postgres
10
+ * target pack against the `'type'` entries key so the family-layer namespace
11
+ * validator accepts (and rejects) entries of this kind.
12
+ */
13
+ declare const PostgresEnumTypeSchema: import("arktype/internal/variants/object.ts").ObjectType<{
14
+ kind: "postgres-enum";
15
+ values: readonly string[];
16
+ name?: string;
17
+ nativeType?: string;
18
+ control?: "managed" | "tolerated" | "external" | "observed";
19
+ }, {}>;
20
+ //#endregion
6
21
  //#region src/core/postgres-schema.d.ts
22
+ type PostgresNamespaceEntries = SqlNamespaceEntries & {
23
+ readonly type?: Readonly<Record<string, PostgresEnumType>>;
24
+ };
7
25
  interface PostgresSchemaInput {
8
26
  readonly id: string;
9
- readonly entries: {
10
- readonly table: Record<string, StorageTable | StorageTableInput>;
11
- readonly type: Record<string, PostgresEnumType | PostgresEnumTypeInput>;
12
- readonly valueSet?: Record<string, StorageValueSet | StorageValueSetInput>;
13
- };
27
+ readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
14
28
  }
15
29
  /**
16
30
  * Postgres target `Namespace` concretion — a Postgres schema (`CREATE
@@ -18,7 +32,7 @@ interface PostgresSchemaInput {
18
32
  * `namespaces: Record<NamespaceId, PostgresSchema>` map populated by
19
33
  * the Postgres PSL interpreter from `namespace { … }` AST buckets.
20
34
  *
21
- * `entries` holds entity-kind slot maps (`table`, `type`). Qualifier
35
+ * `entries` holds entity-kind maps (`table`, `type`). Qualifier
22
36
  * emission is the rendering seam: DDL / SQL emission asks the namespace
23
37
  * for its qualifier (`"<schema>"`) or for a qualified table name
24
38
  * (`"<schema>"."<table>"`) and consumes the result polymorphically.
@@ -37,12 +51,11 @@ declare class PostgresSchema extends NamespaceBase {
37
51
  static unbound: PostgresUnboundSchema;
38
52
  readonly kind: 'schema';
39
53
  readonly id: string;
40
- readonly entries: Readonly<{
41
- readonly table: Readonly<Record<string, StorageTable>>;
42
- readonly type: Readonly<Record<string, PostgresEnumType>>;
43
- readonly valueSet?: Readonly<Record<string, StorageValueSet>>;
44
- }>;
54
+ readonly entries: PostgresNamespaceEntries;
45
55
  constructor(input: PostgresSchemaInput);
56
+ get table(): Readonly<Record<string, StorageTable>>;
57
+ get type(): Readonly<Record<string, PostgresEnumType>>;
58
+ get valueSet(): Readonly<Record<string, StorageValueSet>> | undefined;
46
59
  /**
47
60
  * The bare schema qualifier as it would appear in a rendered SQL
48
61
  * fragment (already quoted). The unbound-schema singleton overrides
@@ -124,5 +137,5 @@ declare class PostgresUnboundSchema extends PostgresSchema {
124
137
  */
125
138
  declare function postgresCreateNamespace(input: SqlNamespaceTablesInput, enumTypes?: Readonly<Record<string, PostgresEnumStorageEntry>>): PostgresSchema;
126
139
  //#endregion
127
- export { type PostgresColumnDefault, PostgresEnumType, type PostgresEnumTypeInput, PostgresSchema, PostgresUnboundSchema, postgresCreateNamespace };
140
+ export { type PostgresColumnDefault, PostgresEnumType, type PostgresEnumTypeInput, PostgresEnumTypeSchema, PostgresSchema, PostgresUnboundSchema, postgresCreateNamespace };
128
141
  //# sourceMappingURL=types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../src/core/postgres-schema.ts"],"mappings":";;;;;;UAiBiB,mBAAA;EAAA,SACN,EAAA;EAAA,SACA,OAAA;IAAA,SACE,KAAA,EAAO,MAAA,SAAe,YAAA,GAAe,iBAAA;IAAA,SACrC,IAAA,EAAM,MAAA,SAAe,gBAAA,GAAmB,qBAAA;IAAA,SACxC,QAAA,GAAW,MAAA,SAAe,eAAA,GAAkB,oBAAA;EAAA;AAAA;;;;;;;;;;;;;;;cAkB5C,cAAA,SAAuB,aAAA;EAnBvB;;;;;;;EAAA,OA2BJ,OAAA,EAAS,qBAAA;EAAA,SAEC,IAAA;EAAA,SACR,EAAA;EAAA,SACA,OAAA,EAAS,QAAA;IAAA,SACP,KAAA,EAAO,QAAA,CAAS,MAAA,SAAe,YAAA;IAAA,SAC/B,IAAA,EAAM,QAAA,CAAS,MAAA,SAAe,gBAAA;IAAA,SAC9B,QAAA,GAAW,QAAA,CAAS,MAAA,SAAe,eAAA;EAAA;cAGlC,KAAA,EAAO,mBAAA;EALD;;;;;EAsDlB,SAAA;EApDsB;;;;;;EA8DtB,YAAA,CAAa,SAAA;EA7EqB;;;;;;EAuFlC,eAAA,CAAgB,IAAA;EA1EL;;;;;;;;EAsFX,mBAAA;EApFsB;;;;;;;;;;;EAmGtB,aAAA,CAAc,QAAA,EAAU,UAAA;AAAA;;;;AAAU;AAwBpC;;;;;;;;;;;;;;;cAAa,qBAAA,SAA8B,cAAA;EAAA,gBACzB,QAAA,EAAU,qBAAA;cAEd,KAAA,GAAQ,mBAAA;EAIX,SAAA;EAIA,YAAA,CAAa,SAAA;EAIb,mBAAA;AAAA;;;;;;;AAkCM;;;;;iBAHD,uBAAA,CACd,KAAA,EAAO,uBAAA,EACP,SAAA,GAAY,QAAA,CAAS,MAAA,SAAe,wBAAA,KACnC,cAAA"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../src/core/postgres-enum-type-schema.ts","../src/core/postgres-schema.ts"],"mappings":";;;;;;;;;;;;cAUa,sBAAA,gDAAsB,UAAA;;;;;;;;;KCUvB,wBAAA,GAA2B,mBAAA;EAAA,SAC5B,IAAA,GAAO,QAAA,CAAS,MAAA,SAAe,gBAAA;AAAA;AAAA,UAGzB,mBAAA;EAAA,SACN,EAAA;EAAA,SACA,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,QAAA,CAAS,MAAA;AAAA;;;;;;;;;;;;AANrD;;;cAuBa,cAAA,SAAuB,aAAA;EAtBM;;;;;;;EAAA,OA8BjC,OAAA,EAAS,qBAAA;EAAA,SAEC,IAAA;EAAA,SACR,EAAA;EAAA,SACA,OAAA,EAAS,wBAAA;cAEN,KAAA,EAAO,mBAAA;EAAA,IAgEf,KAAA,IAAS,QAAA,CAAS,MAAA,SAAe,YAAA;EAAA,IAIjC,IAAA,IAAQ,QAAA,CAAS,MAAA,SAAe,gBAAA;EAAA,IAIhC,QAAA,IAAY,QAAA,CAAS,MAAA,SAAe,eAAA;EAvGW;;;;;EAgHnD,SAAA;EAjHS;;;;;;EA2HT,YAAA,CAAa,SAAA;EA1H4C;AAiB3D;;;;;EAmHE,eAAA,CAAgB,IAAA;EArCqB;;;;;;;;EAiDrC,mBAAA;EAewB;;;;;;;;;;;EAAxB,aAAA,CAAc,QAAA,EAAU,UAAA;AAAA;;;;;;;;;;;;;;;;;;;;cAwBb,qBAAA,SAA8B,cAAA;EAAA,gBACzB,QAAA,EAAU,qBAAA;cAEd,KAAA,GAAQ,mBAAA;EAIX,SAAA;EAIA,YAAA,CAAa,SAAA;EAIb,mBAAA;AAAA;;;;;;;;AAAmB;AA+B9B;;;iBAAgB,uBAAA,CACd,KAAA,EAAO,uBAAA,EACP,SAAA,GAAY,QAAA,CAAS,MAAA,SAAe,wBAAA,KACnC,cAAA"}
package/dist/types.mjs CHANGED
@@ -1,3 +1,4 @@
1
1
  import { t as PostgresEnumType } from "./postgres-enum-type-DPKqCBem.mjs";
2
- import { i as postgresCreateNamespace, n as PostgresUnboundSchema, t as PostgresSchema } from "./postgres-schema-BAgkIU9u.mjs";
3
- export { PostgresEnumType, PostgresSchema, PostgresUnboundSchema, postgresCreateNamespace };
2
+ import { t as PostgresEnumTypeSchema } from "./postgres-enum-type-schema-DZBTtvBF.mjs";
3
+ import { i as postgresCreateNamespace, n as PostgresUnboundSchema, t as PostgresSchema } from "./postgres-schema-C7c9rhGk.mjs";
4
+ export { PostgresEnumType, PostgresEnumTypeSchema, PostgresSchema, PostgresUnboundSchema, postgresCreateNamespace };
package/package.json CHANGED
@@ -1,32 +1,32 @@
1
1
  {
2
2
  "name": "@prisma-next/target-postgres",
3
- "version": "0.13.0-dev.25",
3
+ "version": "0.13.0-dev.27",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "Postgres target pack for Prisma Next",
8
8
  "dependencies": {
9
- "@prisma-next/cli": "0.13.0-dev.25",
10
- "@prisma-next/contract": "0.13.0-dev.25",
11
- "@prisma-next/errors": "0.13.0-dev.25",
12
- "@prisma-next/family-sql": "0.13.0-dev.25",
13
- "@prisma-next/framework-components": "0.13.0-dev.25",
14
- "@prisma-next/migration-tools": "0.13.0-dev.25",
15
- "@prisma-next/ts-render": "0.13.0-dev.25",
16
- "@prisma-next/sql-contract": "0.13.0-dev.25",
17
- "@prisma-next/sql-errors": "0.13.0-dev.25",
18
- "@prisma-next/sql-operations": "0.13.0-dev.25",
19
- "@prisma-next/sql-relational-core": "0.13.0-dev.25",
20
- "@prisma-next/sql-schema-ir": "0.13.0-dev.25",
21
- "@prisma-next/utils": "0.13.0-dev.25",
9
+ "@prisma-next/cli": "0.13.0-dev.27",
10
+ "@prisma-next/contract": "0.13.0-dev.27",
11
+ "@prisma-next/errors": "0.13.0-dev.27",
12
+ "@prisma-next/family-sql": "0.13.0-dev.27",
13
+ "@prisma-next/framework-components": "0.13.0-dev.27",
14
+ "@prisma-next/migration-tools": "0.13.0-dev.27",
15
+ "@prisma-next/ts-render": "0.13.0-dev.27",
16
+ "@prisma-next/sql-contract": "0.13.0-dev.27",
17
+ "@prisma-next/sql-errors": "0.13.0-dev.27",
18
+ "@prisma-next/sql-operations": "0.13.0-dev.27",
19
+ "@prisma-next/sql-relational-core": "0.13.0-dev.27",
20
+ "@prisma-next/sql-schema-ir": "0.13.0-dev.27",
21
+ "@prisma-next/utils": "0.13.0-dev.27",
22
22
  "@standard-schema/spec": "^1.1.0",
23
23
  "arktype": "^2.2.0",
24
24
  "pathe": "^2.0.3"
25
25
  },
26
26
  "devDependencies": {
27
- "@prisma-next/test-utils": "0.13.0-dev.25",
28
- "@prisma-next/tsconfig": "0.13.0-dev.25",
29
- "@prisma-next/tsdown": "0.13.0-dev.25",
27
+ "@prisma-next/test-utils": "0.13.0-dev.27",
28
+ "@prisma-next/tsconfig": "0.13.0-dev.27",
29
+ "@prisma-next/tsdown": "0.13.0-dev.27",
30
30
  "tsdown": "0.22.1",
31
31
  "typescript": "5.9.3",
32
32
  "vitest": "4.1.8"
@@ -5,8 +5,8 @@ import type {
5
5
  AuthoringTypeNamespace,
6
6
  } from '@prisma-next/framework-components/authoring';
7
7
  import type { PostgresEnumStorageEntry } from '@prisma-next/sql-contract/types';
8
- import { PostgresEnumTypeSchema } from '@prisma-next/sql-contract/validators';
9
8
  import { PostgresEnumType, type PostgresEnumTypeInput } from './postgres-enum-type';
9
+ import { PostgresEnumTypeSchema } from './postgres-enum-type-schema';
10
10
 
11
11
  export const postgresAuthoringTypes = {} as const satisfies AuthoringTypeNamespace;
12
12
 
@@ -1,11 +1,11 @@
1
1
  import type { Contract } from '@prisma-next/contract/types';
2
2
  import type { ControlPolicySubject } from '@prisma-next/family-sql/control';
3
3
  import type { SchemaIssue } from '@prisma-next/framework-components/control';
4
- import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
4
+ import { entityAt, UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
5
5
  import {
6
6
  isPostgresEnumStorageEntry,
7
7
  type SqlStorage,
8
- storageTableAt,
8
+ type StorageTable,
9
9
  } from '@prisma-next/sql-contract/types';
10
10
  import { ifDefined } from '@prisma-next/utils/defined';
11
11
  import { isPostgresSchema } from '../postgres-schema';
@@ -43,7 +43,11 @@ function resolveNamespaceIdForTable(
43
43
  ddlSchemaName: string | undefined,
44
44
  ): string {
45
45
  for (const namespaceId of Object.keys(contract.storage.namespaces)) {
46
- const table = storageTableAt(contract.storage, namespaceId, tableName);
46
+ const table = entityAt<StorageTable>(contract.storage, {
47
+ namespaceId,
48
+ entityKind: 'table',
49
+ entityName: tableName,
50
+ });
47
51
  if (!table) continue;
48
52
  if (
49
53
  ddlSchemaName === undefined ||
@@ -122,7 +126,7 @@ export function resolvePostgresCallControlPolicySubject(
122
126
  ? resolveNamespaceIdForDdlSchema(contract, callFields.schemaName)
123
127
  : UNBOUND_NAMESPACE_ID;
124
128
  const ns = contract.storage.namespaces[namespaceId];
125
- const rawEnum = isPostgresSchema(ns) ? ns.entries.type[callFields.typeName] : undefined;
129
+ const rawEnum = isPostgresSchema(ns) ? ns.type[callFields.typeName] : undefined;
126
130
  const controlPolicy = isPostgresEnumStorageEntry(rawEnum) ? rawEnum.control : undefined;
127
131
  return {
128
132
  namespaceId,
@@ -138,7 +142,11 @@ export function resolvePostgresCallControlPolicySubject(
138
142
  callFields.tableName,
139
143
  callFields.schemaName,
140
144
  );
141
- const table = storageTableAt(contract.storage, namespaceId, callFields.tableName);
145
+ const table = entityAt<StorageTable>(contract.storage, {
146
+ namespaceId,
147
+ entityKind: 'table',
148
+ entityName: callFields.tableName,
149
+ });
142
150
  const tableControlPolicy = table?.control;
143
151
  return {
144
152
  namespaceId,
@@ -205,7 +213,7 @@ export function resolvePostgresIssueControlPolicySubject(
205
213
  const namespaceId =
206
214
  'namespaceId' in issue && issue.namespaceId ? issue.namespaceId : UNBOUND_NAMESPACE_ID;
207
215
  const ns = contract.storage.namespaces[namespaceId];
208
- const rawEnum = isPostgresSchema(ns) ? ns.entries.type[issue.typeName] : undefined;
216
+ const rawEnum = isPostgresSchema(ns) ? ns.type[issue.typeName] : undefined;
209
217
  const controlPolicy = isPostgresEnumStorageEntry(rawEnum) ? rawEnum.control : undefined;
210
218
  return {
211
219
  namespaceId,
@@ -220,7 +228,11 @@ export function resolvePostgresIssueControlPolicySubject(
220
228
  'namespaceId' in issue && issue.namespaceId
221
229
  ? issue.namespaceId
222
230
  : resolveNamespaceIdForTable(contract, issue.table, undefined);
223
- const table = storageTableAt(contract.storage, namespaceId, issue.table);
231
+ const table = entityAt<StorageTable>(contract.storage, {
232
+ namespaceId,
233
+ entityKind: 'table',
234
+ entityName: issue.table,
235
+ });
224
236
  return {
225
237
  namespaceId,
226
238
  ...ifDefined('explicitNodeControlPolicy', table?.control),
@@ -81,7 +81,7 @@ function locateNamespaceTypeInStorage(
81
81
  typeName: string,
82
82
  ): unknown {
83
83
  const ns = storage.namespaces[namespaceId];
84
- return isPostgresSchema(ns) ? ns.entries.type[typeName] : undefined;
84
+ return isPostgresSchema(ns) ? ns.type[typeName] : undefined;
85
85
  }
86
86
 
87
87
  // ============================================================================
@@ -97,9 +97,9 @@ export function tableAt(
97
97
  namespaceId: string,
98
98
  tableName: string,
99
99
  ): StorageTable | undefined {
100
- // Namespace.tables is typed as Record<string, IRNode> at the interface level;
101
- // SQL family namespaces always hold StorageTable instances.
102
- return storage.namespaces[namespaceId]?.entries.table[tableName] as StorageTable | undefined;
100
+ const ns = storage.namespaces[namespaceId];
101
+ if (ns === undefined) return undefined;
102
+ return ns.entries.table?.[tableName];
103
103
  }
104
104
 
105
105
  /**
@@ -141,7 +141,7 @@ const DEFAULT_ENUM_NAMESPACE_ID = 'public';
141
141
  function namespaceHasEnum(storage: SqlStorage, namespaceId: string, typeName: string): boolean {
142
142
  const ns = storage.namespaces[namespaceId];
143
143
  if (!isPostgresSchema(ns)) return false;
144
- return ns.entries.type[typeName] !== undefined;
144
+ return ns.type[typeName] !== undefined;
145
145
  }
146
146
 
147
147
  /**
@@ -463,8 +463,7 @@ function enumRebuildCallRecipe(
463
463
  // same-named enums in distinct namespaces keep their columns disjoint.
464
464
  const columnRefs: { namespaceId: string; table: string; column: string }[] = [];
465
465
  for (const [nsId, ns] of Object.entries(ctx.toContract.storage.namespaces)) {
466
- for (const [tableName, tableNode] of Object.entries(ns.entries.table)) {
467
- const table = tableNode as StorageTable;
466
+ for (const [tableName, table] of Object.entries(ns.entries.table ?? {})) {
468
467
  for (const [columnName, column] of Object.entries(table.columns)) {
469
468
  if (
470
469
  column.typeRef === typeName &&
@@ -667,9 +666,7 @@ function collectPostgresEnumTypes(storage: SqlStorage): ReadonlyMap<string, Post
667
666
  const result = new Map<string, PostgresEnumType>();
668
667
  for (const [nsId, ns] of Object.entries(storage.namespaces)) {
669
668
  if (!isPostgresSchema(ns)) continue;
670
- for (const [name, instance] of Object.entries(ns.entries.type).sort(([a], [b]) =>
671
- a.localeCompare(b),
672
- )) {
669
+ for (const [name, instance] of Object.entries(ns.type).sort(([a], [b]) => a.localeCompare(b))) {
673
670
  if (instance instanceof PostgresEnumType) {
674
671
  result.set(enumCompoundKey(nsId, name), instance);
675
672
  }
@@ -688,7 +685,7 @@ function collectContractChecks(
688
685
  tableName: string,
689
686
  ): ReadonlyArray<{ name: string; column: string; permittedValues: readonly string[] }> {
690
687
  const ns = storage.namespaces[namespaceId];
691
- const tableRaw = ns?.entries.table[tableName];
688
+ const tableRaw = ns !== undefined ? ns.entries.table?.[tableName] : undefined;
692
689
  if (!(tableRaw instanceof StorageTable)) return [];
693
690
  const checks = tableRaw.checks;
694
691
  if (!checks || checks.length === 0) return [];
@@ -734,7 +731,7 @@ export const checkConstraintPlanCallStrategy: CallMigrationStrategy = (issues, c
734
731
  const handledIssueKeys = new Set<string>();
735
732
 
736
733
  for (const [namespaceId, ns] of Object.entries(ctx.toContract.storage.namespaces)) {
737
- for (const tableName of Object.keys(ns.entries.table)) {
734
+ for (const tableName of Object.keys(ns.entries.table ?? {})) {
738
735
  const contractChecks = collectContractChecks(ctx.toContract.storage, namespaceId, tableName);
739
736
  if (contractChecks.length === 0) continue;
740
737
 
@@ -15,11 +15,12 @@ import {
15
15
  UNBOUND_NAMESPACE_ID,
16
16
  } from '@prisma-next/framework-components/ir';
17
17
  import type { SqlNamespaceTablesInput, SqlStorage } from '@prisma-next/sql-contract/types';
18
- import { blindCast } from '@prisma-next/utils/casts';
18
+ import { blindCast, castAs } from '@prisma-next/utils/casts';
19
19
  import type { JsonObject } from '@prisma-next/utils/json';
20
20
  import type { Type } from 'arktype';
21
21
  import { postgresAuthoringEntityTypes } from './authoring';
22
22
  import type { PostgresEnumType } from './postgres-enum-type';
23
+ import { PostgresEnumTypeSchema } from './postgres-enum-type-schema';
23
24
  import { isPostgresSchema, PostgresSchema } from './postgres-schema';
24
25
 
25
26
  const POSTGRES_AUTHORING_CTX: AuthoringEntityContext = {
@@ -38,27 +39,21 @@ function isAuthoringEntityTypeFactoryOutput(
38
39
  }
39
40
 
40
41
  /**
41
- * Walks a pack's entity-type namespace tree and emits the maps the
42
- * family base consumes hydrators and validator-schema fragments, both
43
- * keyed by the descriptor's `discriminator`.
42
+ * Walks a pack's entity-type namespace tree and emits hydration factories
43
+ * keyed by the descriptor's `discriminator`. Used for `storage.types`
44
+ * (codec-triple hydration). Namespace entries hydration dispatches by
45
+ * entries key, not discriminator — handled by `hydrateEntriesKind`.
44
46
  */
45
- function collectEntityRegistryContributions(namespace: AuthoringEntityTypeNamespace): {
46
- readonly entityTypeRegistry: ReadonlyMap<string, SqlEntityHydrationFactory>;
47
- readonly validatorFragments: ReadonlyMap<string, Type<unknown>>;
48
- } {
49
- const entityTypeRegistry = new Map<string, SqlEntityHydrationFactory>();
50
- const validatorFragments = new Map<string, Type<unknown>>();
47
+ function collectStorageTypesHydrators(
48
+ namespace: AuthoringEntityTypeNamespace,
49
+ ): ReadonlyMap<string, SqlEntityHydrationFactory> {
50
+ const registry = new Map<string, SqlEntityHydrationFactory>();
51
51
  const walk = (node: AuthoringEntityTypeNamespace): void => {
52
52
  for (const value of Object.values(node)) {
53
53
  if (isAuthoringEntityTypeDescriptor(value)) {
54
54
  if (isAuthoringEntityTypeFactoryOutput(value.output)) {
55
55
  const { factory } = value.output;
56
- entityTypeRegistry.set(value.discriminator, (raw) =>
57
- factory(raw, POSTGRES_AUTHORING_CTX),
58
- );
59
- }
60
- if (value.validatorSchema !== undefined) {
61
- validatorFragments.set(value.discriminator, value.validatorSchema);
56
+ registry.set(value.discriminator, (raw) => factory(raw, POSTGRES_AUTHORING_CTX));
62
57
  }
63
58
  continue;
64
59
  }
@@ -68,15 +63,47 @@ function collectEntityRegistryContributions(namespace: AuthoringEntityTypeNamesp
68
63
  }
69
64
  };
70
65
  walk(namespace);
71
- return { entityTypeRegistry, validatorFragments };
66
+ return registry;
72
67
  }
73
68
 
69
+ // Pack-contributed validator schemas keyed by entries key: postgres registers
70
+ // 'type' → the inner name→entry map schema. The family base composes these
71
+ // into the single registry alongside SQL core's 'table'/'valueSet' via
72
+ // createSqlEntrySchemaRegistry.
73
+ const POSTGRES_VALIDATOR_REGISTRY: ReadonlyMap<string, Type<unknown>> = new Map<
74
+ string,
75
+ Type<unknown>
76
+ >([['type', castAs<Type<unknown>>(PostgresEnumTypeSchema)]]);
77
+
74
78
  export class PostgresContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {
79
+ private readonly enumFactory: SqlEntityHydrationFactory | undefined;
80
+
75
81
  constructor() {
76
- const { entityTypeRegistry, validatorFragments } = collectEntityRegistryContributions(
77
- postgresAuthoringEntityTypes,
78
- );
79
- super(entityTypeRegistry, validatorFragments);
82
+ const storageTypesHydrators = collectStorageTypesHydrators(postgresAuthoringEntityTypes);
83
+ super(storageTypesHydrators, POSTGRES_VALIDATOR_REGISTRY);
84
+ this.enumFactory = storageTypesHydrators.get('postgres-enum');
85
+ }
86
+
87
+ protected override hydrateEntriesKind(
88
+ key: string,
89
+ innerMap: unknown,
90
+ ): Record<string, unknown> | undefined {
91
+ if (key === 'type') {
92
+ if (innerMap === null || typeof innerMap !== 'object' || Array.isArray(innerMap)) {
93
+ return {};
94
+ }
95
+ return Object.fromEntries(
96
+ Object.entries(
97
+ blindCast<Record<string, unknown>, 'checked object, non-null, non-array above'>(innerMap),
98
+ ).map(([name, entry]) => [
99
+ name,
100
+ blindCast<PostgresEnumType, 'postgres-enum factory returns PostgresEnumType'>(
101
+ this.enumFactory !== undefined ? this.enumFactory(entry) : entry,
102
+ ),
103
+ ]),
104
+ );
105
+ }
106
+ return super.hydrateEntriesKind(key, innerMap);
80
107
  }
81
108
 
82
109
  protected override hydrateSqlNamespaceEntry(
@@ -88,43 +115,38 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
88
115
  }
89
116
  const hydrated = blindCast<
90
117
  SqlNamespaceTablesInput,
91
- 'super.hydrateSqlNamespaceEntry returns the tables form when raw is not a NamespaceBase'
118
+ 'super.hydrateSqlNamespaceEntry returns SqlNamespaceTablesInput when raw is not a NamespaceBase'
92
119
  >(super.hydrateSqlNamespaceEntry(nsId, raw));
93
120
  const { id, entries } = hydrated;
94
121
 
95
- // Extract the postgres-specific `type` slot directly from raw input.
96
- // The family base handles the `table` slot; the postgres target owns `type`.
97
- const rawRecord = raw as Record<string, unknown>;
98
- const rawEntries = rawRecord['entries'];
99
- let typeSlot: Record<string, PostgresEnumType> | undefined;
100
- if (rawEntries !== null && typeof rawEntries === 'object' && !Array.isArray(rawEntries)) {
101
- const rawTypeSlot = (rawEntries as Record<string, unknown>)['type'];
102
- if (rawTypeSlot !== null && typeof rawTypeSlot === 'object' && !Array.isArray(rawTypeSlot)) {
103
- const enumFactory = this.entityTypeRegistry.get('postgres-enum');
104
- typeSlot = Object.fromEntries(
105
- Object.entries(rawTypeSlot as Record<string, unknown>).map(([name, entry]) => [
106
- name,
107
- blindCast<PostgresEnumType, 'postgres-enum factory returns PostgresEnumType'>(
108
- enumFactory !== undefined ? enumFactory(entry) : entry,
109
- ),
110
- ]),
111
- );
112
- }
113
- }
114
-
115
- const valueSetSlot = entries.valueSet;
116
- const hasValueSets = valueSetSlot !== undefined && Object.keys(valueSetSlot).length > 0;
117
- const emptyTables = Object.keys(entries.table).length === 0;
118
- const emptyTypes = !typeSlot || Object.keys(typeSlot).length === 0;
122
+ const typeEntries = blindCast<
123
+ Record<string, PostgresEnumType> | undefined,
124
+ 'hydrateEntriesKind populates entries[type] with PostgresEnumType instances'
125
+ >(entries['type']);
126
+ const valueSetEntries = entries['valueSet'];
127
+ const hasValueSets = valueSetEntries !== undefined && Object.keys(valueSetEntries).length > 0;
128
+ const tableEntries = entries['table'] ?? {};
129
+ const emptyTables = Object.keys(tableEntries).length === 0;
130
+ const emptyTypes = !typeEntries || Object.keys(typeEntries).length === 0;
119
131
  if (id === UNBOUND_NAMESPACE_ID && emptyTables && emptyTypes && !hasValueSets) {
120
132
  return PostgresSchema.unbound;
121
133
  }
122
134
  return new PostgresSchema({
123
135
  id,
124
136
  entries: {
125
- table: entries.table,
126
- type: typeSlot ?? {},
127
- ...(hasValueSets ? { valueSet: valueSetSlot } : {}),
137
+ table: blindCast<
138
+ Record<string, unknown>,
139
+ 'table entries are StorageTable instances after base hydration'
140
+ >(tableEntries),
141
+ type: typeEntries ?? {},
142
+ ...(hasValueSets
143
+ ? {
144
+ valueSet: blindCast<
145
+ Record<string, unknown>,
146
+ 'valueSet entries are StorageValueSet instances after base hydration'
147
+ >(valueSetEntries),
148
+ }
149
+ : {}),
128
150
  },
129
151
  });
130
152
  }
@@ -142,7 +164,7 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
142
164
  kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',
143
165
  entries: {
144
166
  table: Object.fromEntries(
145
- Object.entries(ns.entries.table).map(([tableName, table]) => [
167
+ Object.entries(ns.entries.table ?? {}).map(([tableName, table]) => [
146
168
  tableName,
147
169
  this.serializeJsonValue(table) as JsonObject,
148
170
  ]),
@@ -170,14 +192,14 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
170
192
 
171
193
  private serializePostgresNamespace(ns: PostgresSchema, isUnboundSlot: boolean): JsonObject {
172
194
  const tablesOut: Record<string, JsonObject> = {};
173
- for (const [tableName, table] of Object.entries(ns.entries.table)) {
195
+ for (const [tableName, table] of Object.entries(ns.table)) {
174
196
  tablesOut[tableName] = this.serializeJsonValue(table) as JsonObject;
175
197
  }
176
198
  const typeOut: Record<string, JsonObject> = {};
177
- for (const [typeName, ty] of Object.entries(ns.entries.type)) {
199
+ for (const [typeName, ty] of Object.entries(ns.type)) {
178
200
  typeOut[typeName] = this.serializeJsonValue(ty) as JsonObject;
179
201
  }
180
- const valueSetEntries = ns.entries.valueSet;
202
+ const valueSetEntries = ns.valueSet;
181
203
  const valueSetOut: Record<string, JsonObject> = {};
182
204
  if (valueSetEntries !== undefined) {
183
205
  for (const [valueSetName, valueSet] of Object.entries(valueSetEntries)) {
@@ -0,0 +1,17 @@
1
+ import { type } from 'arktype';
2
+
3
+ const ControlPolicySchema = type("'managed' | 'tolerated' | 'external' | 'observed'");
4
+
5
+ /**
6
+ * Arktype validator for a `postgres-enum` entry under
7
+ * `storage.namespaces[id].entries.type[name]`. Registered by the Postgres
8
+ * target pack against the `'type'` entries key so the family-layer namespace
9
+ * validator accepts (and rejects) entries of this kind.
10
+ */
11
+ export const PostgresEnumTypeSchema = type({
12
+ kind: "'postgres-enum'",
13
+ 'name?': 'string',
14
+ 'nativeType?': 'string',
15
+ values: type.string.array().readonly(),
16
+ 'control?': ControlPolicySchema,
17
+ });