@prisma-next/target-postgres 0.14.0-dev.52 → 0.14.0-dev.54

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 (41) hide show
  1. package/dist/{authoring-ohGMgi8g.mjs → authoring-Bd9Tt3E3.mjs} +26 -3
  2. package/dist/authoring-Bd9Tt3E3.mjs.map +1 -0
  3. package/dist/control.mjs +174 -31
  4. package/dist/control.mjs.map +1 -1
  5. package/dist/{descriptor-meta-Cok-1QEK.mjs → descriptor-meta-_pn08mka.mjs} +2 -2
  6. package/dist/{descriptor-meta-Cok-1QEK.mjs.map → descriptor-meta-_pn08mka.mjs.map} +1 -1
  7. package/dist/{diff-database-schema-BivMht-X.mjs → diff-database-schema-CUSoT1Dk.mjs} +4 -3
  8. package/dist/diff-database-schema-CUSoT1Dk.mjs.map +1 -0
  9. package/dist/diff-database-schema.d.mts +1 -1
  10. package/dist/diff-database-schema.d.mts.map +1 -1
  11. package/dist/diff-database-schema.mjs +1 -1
  12. package/dist/migration.mjs +1 -1
  13. package/dist/pack.mjs +1 -1
  14. package/dist/{planner-r4iLpxD7.mjs → planner-ChE2d2-k.mjs} +4 -4
  15. package/dist/{planner-r4iLpxD7.mjs.map → planner-ChE2d2-k.mjs.map} +1 -1
  16. package/dist/{planner-produced-postgres-migration-kVlK1Dts.mjs → planner-produced-postgres-migration-qTr4KVlt.mjs} +2 -2
  17. package/dist/{planner-produced-postgres-migration-kVlK1Dts.mjs.map → planner-produced-postgres-migration-qTr4KVlt.mjs.map} +1 -1
  18. package/dist/planner-produced-postgres-migration.mjs +1 -1
  19. package/dist/planner.d.mts +1 -1
  20. package/dist/planner.mjs +2 -2
  21. package/dist/{postgres-contract-view-C5RSIHFm.mjs → postgres-contract-view-BUjK3NeM.mjs} +2 -2
  22. package/dist/{postgres-contract-view-C5RSIHFm.mjs.map → postgres-contract-view-BUjK3NeM.mjs.map} +1 -1
  23. package/dist/{postgres-database-schema-node-C9bTuMrd.d.mts → postgres-database-schema-node-UpzA0Ug5.d.mts} +15 -2
  24. package/dist/{postgres-database-schema-node-C9bTuMrd.d.mts.map → postgres-database-schema-node-UpzA0Ug5.d.mts.map} +1 -1
  25. package/dist/{postgres-migration-CiA7wpQD.mjs → postgres-migration-DqGd8mAu.mjs} +2 -2
  26. package/dist/{postgres-migration-CiA7wpQD.mjs.map → postgres-migration-DqGd8mAu.mjs.map} +1 -1
  27. package/dist/{postgres-table-schema-node-BgaSrxYN.mjs → postgres-table-schema-node-BZWWEo7B.mjs} +12 -1
  28. package/dist/postgres-table-schema-node-BZWWEo7B.mjs.map +1 -0
  29. package/dist/runtime.mjs +1 -1
  30. package/dist/types.d.mts +2 -2
  31. package/dist/types.mjs +1 -1
  32. package/package.json +20 -20
  33. package/src/core/authoring.ts +29 -3
  34. package/src/core/migrations/diff-database-schema.ts +1 -0
  35. package/src/core/psl-infer/infer-psl-contract.ts +288 -31
  36. package/src/core/psl-infer/postgres-type-map.ts +0 -29
  37. package/src/core/schema-ir/postgres-namespace-schema-node.ts +19 -0
  38. package/src/exports/types.ts +1 -0
  39. package/dist/authoring-ohGMgi8g.mjs.map +0 -1
  40. package/dist/diff-database-schema-BivMht-X.mjs.map +0 -1
  41. package/dist/postgres-table-schema-node-BgaSrxYN.mjs.map +0 -1
@@ -33,9 +33,32 @@ function readListRefParams(block, key) {
33
33
  if (param?.kind !== "list") return [];
34
34
  return param.items.flatMap((item) => item.kind === "ref" ? [item.identifier] : []);
35
35
  }
36
+ /**
37
+ * Unwraps a quoted PSL string argument, inverting the printer's
38
+ * `escapePslString` escapes (`\\`, `\"`, `\n`, `\r`). An unknown escape
39
+ * sequence is kept verbatim, matching the printer-side `unescapePslString`
40
+ * convention.
41
+ */
36
42
  function unwrapQuotedString(raw) {
37
- if (raw.startsWith("\"") && raw.endsWith("\"") && raw.length >= 2) return raw.slice(1, -1).replace(/\\"/g, "\"");
38
- return raw;
43
+ if (!(raw.startsWith("\"") && raw.endsWith("\"") && raw.length >= 2)) return raw;
44
+ const inner = raw.slice(1, -1);
45
+ let result = "";
46
+ for (let i = 0; i < inner.length; i++) {
47
+ if (inner[i] !== "\\" || i + 1 >= inner.length) {
48
+ result += inner[i];
49
+ continue;
50
+ }
51
+ const next = inner[i + 1];
52
+ if (next === "\\" || next === "\"") result += next;
53
+ else if (next === "n") result += "\n";
54
+ else if (next === "r") result += "\r";
55
+ else {
56
+ result += "\\";
57
+ result += next;
58
+ }
59
+ i++;
60
+ }
61
+ return result;
39
62
  }
40
63
  function lowerRlsPolicyFromBlock(block, _ctx) {
41
64
  const prefix = block.name;
@@ -361,4 +384,4 @@ const postgresAuthoringFieldPresets = {
361
384
  //#endregion
362
385
  export { postgresAuthoringTypes as i, postgresAuthoringFieldPresets as n, postgresAuthoringPslBlockDescriptors as r, postgresAuthoringEntityTypes as t };
363
386
 
364
- //# sourceMappingURL=authoring-ohGMgi8g.mjs.map
387
+ //# sourceMappingURL=authoring-Bd9Tt3E3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authoring-Bd9Tt3E3.mjs","names":[],"sources":["../src/core/authoring.ts"],"sourcesContent":["import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';\nimport type {\n AuthoringEntityContext,\n AuthoringEntityTypeFactoryOutput,\n AuthoringEntityTypeNamespace,\n AuthoringFieldNamespace,\n AuthoringPslBlockDescriptorNamespace,\n AuthoringTypeNamespace,\n PslExtensionBlock,\n} from '@prisma-next/framework-components/authoring';\nimport type { SqlValueSetDerivingEntityTypeOutput } from '@prisma-next/sql-contract/value-set-derivation-hook';\nimport { PG_ENUM_CODEC_ID } from './codec-ids';\nimport { PostgresNativeEnum } from './postgres-native-enum';\nimport { PostgresRlsPolicy } from './postgres-rls-policy';\nimport { PostgresRole, type PostgresRoleInput } from './postgres-role';\nimport {\n PostgresNativeEnumSchema,\n PostgresRlsPolicySchema,\n PostgresRoleSchema,\n} from './postgres-validators';\nimport { computeContentHash, normalizePredicate } from './rls/canonicalize';\n\n/**\n * `pg.enum(<ref>)` registers as an ordinary type constructor whose sole\n * positional argument names a `native_enum` entity instead of carrying a\n * literal value. The interpreter resolves the ref to the `native_enum`\n * entity generically (driven by `entityRefArg`); the `pg/enum@1` codec\n * descriptor's `columnFromEntity` hook (see `codecs.ts`) converts that\n * entity into the column's `typeParams` and native type.\n */\nexport const postgresAuthoringTypes = {\n pg: {\n enum: {\n kind: 'typeConstructor',\n entityRefArg: { index: 0, entityKind: 'native_enum' },\n output: {\n codecId: PG_ENUM_CODEC_ID,\n },\n },\n },\n} as const satisfies AuthoringTypeNamespace;\n\nexport interface RlsPolicyExtensionBlock extends PslExtensionBlock {\n readonly namespaceId: string;\n}\n\nfunction readRefParam(block: PslExtensionBlock, key: string): string | undefined {\n const param = block.parameters[key];\n return param?.kind === 'ref' ? param.identifier : undefined;\n}\n\nfunction readValueParam(block: PslExtensionBlock, key: string): string | undefined {\n const param = block.parameters[key];\n return param?.kind === 'value' ? param.raw : undefined;\n}\n\nfunction readListRefParams(block: PslExtensionBlock, key: string): string[] {\n const param = block.parameters[key];\n if (param?.kind !== 'list') return [];\n return param.items.flatMap((item) => (item.kind === 'ref' ? [item.identifier] : []));\n}\n\n/**\n * Unwraps a quoted PSL string argument, inverting the printer's\n * `escapePslString` escapes (`\\\\`, `\\\"`, `\\n`, `\\r`). An unknown escape\n * sequence is kept verbatim, matching the printer-side `unescapePslString`\n * convention.\n */\nfunction unwrapQuotedString(raw: string): string {\n if (!(raw.startsWith('\"') && raw.endsWith('\"') && raw.length >= 2)) {\n return raw;\n }\n const inner = raw.slice(1, -1);\n let result = '';\n for (let i = 0; i < inner.length; i++) {\n if (inner[i] !== '\\\\' || i + 1 >= inner.length) {\n result += inner[i];\n continue;\n }\n const next = inner[i + 1];\n if (next === '\\\\' || next === '\"') {\n result += next;\n } else if (next === 'n') {\n result += '\\n';\n } else if (next === 'r') {\n result += '\\r';\n } else {\n result += '\\\\';\n result += next;\n }\n i++;\n }\n return result;\n}\n\nfunction lowerRlsPolicyFromBlock(\n block: RlsPolicyExtensionBlock,\n _ctx: AuthoringEntityContext,\n): PostgresRlsPolicy {\n const prefix = block.name;\n const targetModelName = readRefParam(block, 'target') ?? '';\n const tableName = targetModelName.charAt(0).toLowerCase() + targetModelName.slice(1);\n const roles = [...readListRefParams(block, 'roles')].sort();\n const using = unwrapQuotedString(readValueParam(block, 'using') ?? '');\n\n const wireHash = computeContentHash({\n using: normalizePredicate(using),\n roles,\n operation: 'select',\n permissive: true,\n });\n const wireName = `${prefix}_${wireHash}`;\n\n return new PostgresRlsPolicy({\n name: wireName,\n prefix,\n tableName,\n namespaceId: block.namespaceId,\n operation: 'select',\n roles,\n using,\n permissive: true,\n });\n}\n\n/**\n * Lowers a `native_enum { memberName = \"value\" … @@map(\"type_name\") }` block\n * into a {@link PostgresNativeEnum}. Members must be authored as explicit\n * `key = \"value\"` pairs — a bare (value-less) member is a diagnostic, not\n * accepted (authoring-design.md §2.1). The parsed `memberName` is only used\n * to duplicate-check and report diagnostics; the lowered entity carries just\n * the member values (a native enum is value-only — the member \"name\" isn't\n * a separate authoring concept from the value). `typeName` comes from\n * `@@map` or defaults to the block name verbatim.\n */\nfunction lowerNativeEnumFromBlock(\n block: PslExtensionBlock,\n ctx: AuthoringEntityContext,\n): PostgresNativeEnum | undefined {\n const sourceId = ctx.sourceId ?? 'unknown';\n const diagnostics = ctx.diagnostics;\n\n const mapAttr = block.blockAttributes.find((a) => a.name === 'map');\n let typeName = block.name;\n if (mapAttr) {\n const rawArg = mapAttr.args[0]?.value;\n const mapped = rawArg !== undefined ? unwrapQuotedString(rawArg) : undefined;\n if (mapped === undefined) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_INVALID_MAP',\n message: `native_enum \"${block.name}\" @@map attribute must have a quoted type-name argument`,\n sourceId,\n span: mapAttr.span,\n });\n return undefined;\n }\n typeName = mapped;\n }\n\n let memberError = false;\n const seenValues = new Set<string>();\n const members: string[] = [];\n for (const [memberName, paramValue] of Object.entries(block.parameters)) {\n if (paramValue.kind === 'bare') {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_BARE_MEMBER',\n message: `native_enum \"${block.name}\" member \"${memberName}\" has no value; members must be authored as \"${memberName} = \\\\\"value\\\\\"\"`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (paramValue.kind !== 'value') continue;\n\n let jsonValue: unknown;\n try {\n jsonValue = JSON.parse(paramValue.raw);\n } catch {\n diagnostics?.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `native_enum \"${block.name}\" member \"${memberName}\" value \"${paramValue.raw}\" is not valid JSON`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (typeof jsonValue !== 'string') {\n diagnostics?.push({\n code: 'PSL_EXTENSION_INVALID_VALUE',\n message: `native_enum \"${block.name}\" member \"${memberName}\" value must be a string`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n if (seenValues.has(jsonValue)) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_DUPLICATE_MEMBER_VALUE',\n message: `native_enum \"${block.name}\": duplicate member value \"${jsonValue}\"`,\n sourceId,\n span: paramValue.span,\n });\n memberError = true;\n continue;\n }\n seenValues.add(jsonValue);\n members.push(jsonValue);\n }\n\n if (memberError) return undefined;\n\n if (members.length === 0) {\n diagnostics?.push({\n code: 'PSL_NATIVE_ENUM_MISSING_MEMBERS',\n message: `native_enum \"${block.name}\" must have at least one member`,\n sourceId,\n span: block.span,\n });\n return undefined;\n }\n\n // `control` stays unset — the effective grade is resolved at read time via `effectiveControlPolicy`, like `StorageTable`/`StorageColumn`.\n return new PostgresNativeEnum({ typeName, members });\n}\n\n/**\n * `native_enum`'s entity-type factory output, checked separately from the assembled\n * `postgresAuthoringEntityTypes` map below: `deriveValueSet` is SQL-family surface\n * ({@link SqlValueSetDerivingEntityTypeOutput}), not part of the framework\n * `AuthoringEntityTypeFactoryOutput` shape, so folding it directly into the map's single\n * `satisfies AuthoringEntityTypeNamespace` check would trip an excess-property error. Checking it\n * here against the intersection of both shapes keeps it structurally valid against each without\n * widening the map's own check.\n */\nconst nativeEnumEntityTypeOutput = {\n factory: lowerNativeEnumFromBlock,\n deriveValueSet: (entity: PostgresNativeEnum) => ({\n kind: 'valueSet' as const,\n values: [...entity.members],\n }),\n} satisfies AuthoringEntityTypeFactoryOutput<PslExtensionBlock, PostgresNativeEnum | undefined> &\n SqlValueSetDerivingEntityTypeOutput;\n\nexport const postgresAuthoringEntityTypes = {\n role: {\n kind: 'entity',\n discriminator: 'role',\n validatorSchema: PostgresRoleSchema,\n output: {\n factory: (input: PostgresRoleInput): PostgresRole => new PostgresRole(input),\n },\n },\n policy: {\n kind: 'entity',\n discriminator: 'policy',\n validatorSchema: PostgresRlsPolicySchema,\n output: {\n factory: lowerRlsPolicyFromBlock,\n },\n },\n native_enum: {\n kind: 'entity',\n discriminator: 'native_enum',\n validatorSchema: PostgresNativeEnumSchema,\n output: nativeEnumEntityTypeOutput,\n },\n} as const satisfies AuthoringEntityTypeNamespace;\n\n/**\n * Field presets contributed by the Postgres target pack.\n *\n * These mirror the PSL scalar-to-codec mapping used by the Postgres adapter\n * (see `createPostgresPslScalarTypeDescriptors`), so that authoring a field\n * via the TS callback surface (e.g. `field.int()`) and via the PSL scalar\n * surface (e.g. `Int`) lowers to byte-identical contracts.\n *\n * The `uuidNative` / `id.uuidv4Native` / `id.uuidv7Native` presets use the\n * native Postgres `uuid` type (codecId `pg/uuid@1`). For cross-target\n * portability use `uuidString` / `id.uuidv4String` / `id.uuidv7String` from\n * the family pack instead.\n */\n/**\n * PSL block descriptor for `policy_select`.\n *\n * The parser learns the block shape from this descriptor; lowering from\n * `PslExtensionBlock` to `PostgresRlsPolicy` is wired in the PSL\n * interpreter (a later dispatch). The `discriminator` matches\n * `PostgresRlsPolicy.kind` so the parsed block node carries the same\n * discriminant as the IR class it will lower to.\n *\n * The `roles` list uses `scope:'cross-space'` because same-namespace\n * role ref resolution requires PSL namespace entries keyed by `refKind`\n * (i.e. `'role'`), which in turn requires the role block discriminator to\n * equal `'role'`. Aligning discriminator with refKind is tracked for\n * slice 4 (cross-space roles). Until then cross-space passes validation\n * unconditionally and the authored role names flow through unchanged.\n */\nexport const postgresAuthoringPslBlockDescriptors = {\n policy_select: {\n kind: 'pslBlock',\n keyword: 'policy_select',\n discriminator: 'policy',\n name: { required: true },\n parameters: {\n target: { kind: 'ref', refKind: 'model', scope: 'same-namespace', required: true },\n roles: {\n kind: 'list',\n of: { kind: 'ref', refKind: 'role', scope: 'cross-space' },\n },\n using: { kind: 'value', codecId: 'pg/text@1', required: true },\n },\n },\n /**\n * PSL block descriptor for `native_enum`.\n *\n * Reuses the existing variadic-block mechanism (the same shape the SQL\n * family's `enum` block ships): the body is an open `memberName = \"value\"`\n * list. `variadicParameters: true` opens the block to arbitrary keys\n * beyond the declared (empty) `parameters` set — the lowering factory\n * (`lowerNativeEnumFromBlock`) turns the variadic entries into ordered\n * members and rejects a bare (value-less) member.\n */\n native_enum: {\n kind: 'pslBlock',\n keyword: 'native_enum',\n discriminator: 'native_enum',\n name: { required: true },\n parameters: {},\n variadicParameters: true,\n },\n} as const satisfies AuthoringPslBlockDescriptorNamespace;\n\nexport const postgresAuthoringFieldPresets = {\n text: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/text@1',\n nativeType: 'text',\n },\n },\n int: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int4@1',\n nativeType: 'int4',\n },\n },\n bigint: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int8@1',\n nativeType: 'int8',\n },\n },\n float: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/float8@1',\n nativeType: 'float8',\n },\n },\n decimal: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/numeric@1',\n nativeType: 'numeric',\n },\n },\n boolean: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bool@1',\n nativeType: 'bool',\n },\n },\n json: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/jsonb@1',\n nativeType: 'jsonb',\n },\n },\n bytes: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bytea@1',\n nativeType: 'bytea',\n },\n },\n dateTime: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n },\n },\n temporal: /* @__PURE__ */ temporalAuthoringPresets({\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n }),\n uuidNative: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n },\n },\n id: {\n uuidv4Native: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n executionDefaults: {\n onCreate: {\n kind: 'generator',\n id: 'uuidv4',\n },\n },\n id: true,\n },\n },\n uuidv7Native: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/uuid@1',\n nativeType: 'uuid',\n executionDefaults: {\n onCreate: {\n kind: 'generator',\n id: 'uuidv7',\n },\n },\n id: true,\n },\n },\n },\n} as const satisfies AuthoringFieldNamespace;\n"],"mappings":"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AgC;CAC3C,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,KAAK;EACH,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,QAAQ;EACN,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAAU;EACR,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAA0B,yCAAyB;EACjD,SAAS;EACT,YAAY;CACd,CAAC;CACD,YAAY;EACV,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,IAAI;EACF,cAAc;GACZ,MAAM;GACN,QAAQ;IACN,SAAS;IACT,YAAY;IACZ,mBAAmB,EACjB,UAAU;KACR,MAAM;KACN,IAAI;IACN,EACF;IACA,IAAI;GACN;EACF;EACA,cAAc;GACZ,MAAM;GACN,QAAQ;IACN,SAAS;IACT,YAAY;IACZ,mBAAmB,EACjB,UAAU;KACR,MAAM;KACN,IAAI;IACN,EACF;IACA,IAAI;GACN;EACF;CACF;AACF"}
package/dist/control.mjs CHANGED
@@ -1,11 +1,12 @@
1
- import { t as postgresTargetDescriptorMeta } from "./descriptor-meta-Cok-1QEK.mjs";
1
+ import { t as PostgresNativeEnum } from "./postgres-native-enum-xdiqmBf_.mjs";
2
+ import { t as postgresTargetDescriptorMeta } from "./descriptor-meta-_pn08mka.mjs";
2
3
  import { n as postgresDiffSubjectEntityKind, r as postgresDiffSubjectGranularity } from "./schema-node-kinds-ClScchhi.mjs";
3
- import { a as PostgresDatabaseSchemaNode } from "./postgres-table-schema-node-BgaSrxYN.mjs";
4
- import { n as diffPostgresSchema, r as contractToPostgresDatabaseSchemaNode } from "./diff-database-schema-BivMht-X.mjs";
4
+ import { a as PostgresDatabaseSchemaNode } from "./postgres-table-schema-node-BZWWEo7B.mjs";
5
+ import { n as diffPostgresSchema, r as contractToPostgresDatabaseSchemaNode } from "./diff-database-schema-CUSoT1Dk.mjs";
5
6
  import { r as renderDefaultLiteral } from "./planner-ddl-builders-B8Nn6nHN.mjs";
6
- import { n as PostgresContractSerializer } from "./postgres-contract-view-C5RSIHFm.mjs";
7
- import { t as createPostgresMigrationPlanner } from "./planner-r4iLpxD7.mjs";
8
- import { UNBOUND_NAMESPACE_ID, coordinateKey, elementCoordinates } from "@prisma-next/framework-components/ir";
7
+ import { n as PostgresContractSerializer } from "./postgres-contract-view-BUjK3NeM.mjs";
8
+ import { t as createPostgresMigrationPlanner } from "./planner-ChE2d2-k.mjs";
9
+ import { UNBOUND_NAMESPACE_ID, coordinateKey, elementCoordinates, isPlainRecord } from "@prisma-next/framework-components/ir";
9
10
  import { blindCast } from "@prisma-next/utils/casts";
10
11
  import { buildNativeTypeExpander, runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
11
12
  import { ifDefined } from "@prisma-next/utils/defined";
@@ -14,7 +15,7 @@ import { APP_SPACE_ID } from "@prisma-next/framework-components/control";
14
15
  import { notOk, ok, okVoid } from "@prisma-next/utils/result";
15
16
  import { SqlSchemaVerifierBase } from "@prisma-next/family-sql/ir";
16
17
  import { SqlQueryError } from "@prisma-next/sql-errors";
17
- import { buildChildRelationField, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, toFieldName, toModelName, toNamedTypeName } from "@prisma-next/family-sql/psl-infer";
18
+ import { buildChildRelationField, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, toEnumMemberName, toEnumName, toFieldName, toModelName, toNamedTypeName } from "@prisma-next/family-sql/psl-infer";
18
19
  import { UNSPECIFIED_PSL_NAMESPACE_ID, makePslNamespace, makePslNamespaceEntries } from "@prisma-next/framework-components/psl-ast";
19
20
  //#region src/core/migrations/runner.ts
20
21
  const LOCK_DOMAIN = "prisma_next.contract.marker";
@@ -752,42 +753,118 @@ function resolveForeignKeys(tables, owners) {
752
753
  function inferPostgresPslContract(tree, describedContracts) {
753
754
  const namespaces = Object.values(tree.namespaces);
754
755
  const owners = describedContractOwners(describedContracts ?? []);
755
- const enumTypeNames = [...new Set(namespaces.flatMap((ns) => ns.nativeEnumTypeNames))];
756
- if (enumTypeNames.length > 0) {
757
- const names = enumTypeNames.join(", ");
758
- throw new Error(`contract infer: the database contains native Postgres enum type(s): ${names}. Native Postgres enums (CREATE TYPE … AS ENUM) are not adoptable by contract infer. Drop the native type and replace each column with a text column carrying a CHECK constraint, then re-run contract infer. The domain enum (enum Name { @@type("pg/text@1") … }) authoring surface generates the required check automatically.`);
756
+ const enumOwners = describedNativeEnumOwnersByTypeName(describedContracts ?? []);
757
+ const enumDefinitions = /* @__PURE__ */ new Map();
758
+ const packOwnedEnumTypesByNamespace = /* @__PURE__ */ new Map();
759
+ const enumNamespaceNames = /* @__PURE__ */ new Set();
760
+ for (const namespace of namespaces) {
761
+ const definitionsForNamespace = new Set(namespace.nativeEnums.map((e) => e.typeName));
762
+ for (const typeName of namespace.nativeEnumTypeNames) if (!definitionsForNamespace.has(typeName)) throw new Error(`contract infer: introspection reported native enum type "${typeName}" in schema "${namespace.schemaName}" without member values — the introspected tree's \`nativeEnumTypeNames\` and \`nativeEnums\` are out of sync (internal invariant).`);
763
+ for (const { typeName, values } of namespace.nativeEnums) {
764
+ const owner = enumOwners.get(coordinateKey({
765
+ namespaceId: namespace.schemaName,
766
+ entityKind: "native_enum",
767
+ entityName: typeName
768
+ }));
769
+ if (owner !== void 0) {
770
+ const owned = packOwnedEnumTypesByNamespace.get(namespace.schemaName) ?? /* @__PURE__ */ new Map();
771
+ owned.set(typeName, owner.spaceId);
772
+ owned.set(`${namespace.schemaName}.${typeName}`, owner.spaceId);
773
+ packOwnedEnumTypesByNamespace.set(namespace.schemaName, owned);
774
+ continue;
775
+ }
776
+ enumDefinitions.set(typeName, values);
777
+ enumNamespaceNames.add(namespace.schemaName);
778
+ }
759
779
  }
760
780
  const tables = {};
761
- for (const namespace of namespaces) for (const [tableName, table] of Object.entries(namespace.tables)) {
762
- if (owners.has(coordinateKey({
763
- namespaceId: namespace.schemaName,
764
- entityKind: "table",
765
- entityName: tableName
766
- }))) continue;
767
- if (tables[tableName] !== void 0) throw new Error(`contract infer: duplicate table name "${tableName}" across schemas is not yet supported (single-namespace PSL inference emits one flat bucket; multi-namespace \`namespace { … }\` output is a later slice).`);
768
- tables[tableName] = new SqlTableIR(table);
781
+ const tableNamespaceNames = /* @__PURE__ */ new Set();
782
+ for (const namespace of namespaces) {
783
+ const ownedEnumTypes = packOwnedEnumTypesByNamespace.get(namespace.schemaName);
784
+ for (const [tableName, table] of Object.entries(namespace.tables)) {
785
+ if (owners.has(coordinateKey({
786
+ namespaceId: namespace.schemaName,
787
+ entityKind: "table",
788
+ entityName: tableName
789
+ }))) continue;
790
+ if (tables[tableName] !== void 0) throw new Error(`contract infer: duplicate table name "${tableName}" across schemas is not yet supported (single-namespace PSL inference emits one flat bucket; multi-namespace \`namespace { … }\` output is a later slice).`);
791
+ if (ownedEnumTypes !== void 0) for (const column of Object.values(table.columns)) {
792
+ const owningSpaceId = ownedEnumTypes.get(column.nativeType);
793
+ if (owningSpaceId !== void 0) throw new Error(`contract infer: column "${tableName}"."${column.name}" is typed by native enum type "${column.nativeType}", which extension pack space "${owningSpaceId}" already describes. A cross-space enum-typed column has no authorable PSL form yet; describe the table in that pack's contract or retype the column before re-running contract infer.`);
794
+ }
795
+ tables[tableName] = new SqlTableIR(table);
796
+ tableNamespaceNames.add(namespace.schemaName);
797
+ }
798
+ }
799
+ let wrapNamespaceName;
800
+ if (enumDefinitions.size > 0) {
801
+ const contentNamespaces = new Set([...enumNamespaceNames, ...tableNamespaceNames]);
802
+ if (contentNamespaces.size > 1) throw new Error(`contract infer: native enum adoption with content across multiple schemas is not yet supported (single-namespace PSL inference emits one \`namespace { … }\` block; multi-namespace output is a later slice). Schemas: ${[...contentNamespaces].sort().join(", ")}.`);
803
+ wrapNamespaceName = [...contentNamespaces][0];
769
804
  }
770
805
  const { tables: resolvedTables, extraRelationsByTable, crossSpaceFieldNamesByTable } = resolveForeignKeys(tables, owners);
771
- return buildPslDocumentAst(new SqlSchemaIR({ tables: resolvedTables }), {
772
- typeMap: createPostgresTypeMap(/* @__PURE__ */ new Set()),
806
+ const schemaIR = new SqlSchemaIR({ tables: resolvedTables });
807
+ const enumTypeNames = new Set(enumDefinitions.keys());
808
+ if (wrapNamespaceName !== void 0) for (const typeName of enumDefinitions.keys()) enumTypeNames.add(`${wrapNamespaceName}.${typeName}`);
809
+ const enumInfo = {
810
+ typeNames: enumTypeNames,
811
+ definitions: enumDefinitions
812
+ };
813
+ return buildPslDocumentAst(schemaIR, {
814
+ typeMap: createPostgresTypeMap(enumInfo.typeNames),
773
815
  defaultMapping: createPostgresDefaultMapping(),
774
- parseRawDefault
816
+ parseRawDefault,
817
+ ...enumDefinitions.size > 0 ? { enumInfo } : {}
775
818
  }, {
776
819
  extraRelationsByTable,
777
820
  crossSpaceFieldNamesByTable
778
- });
821
+ }, wrapNamespaceName);
779
822
  }
780
- function buildPslDocumentAst(schemaIR, options, foreignKeyExtras) {
823
+ /**
824
+ * Native-enum ownership index for pack subtraction, keyed by TYPE NAME
825
+ * coordinate. A pack contract keys `entries.native_enum` by HANDLE name
826
+ * (`AalLevel`) while introspection sees the Postgres type name (`aal_level`);
827
+ * the entity's `typeName` field carries the mapping, so this walk indexes by
828
+ * it rather than reusing {@link describedContractOwners}' entries-key
829
+ * coordinates.
830
+ *
831
+ * Reads `entries.native_enum` directly: the kind map is carried
832
+ * non-enumerable on `PostgresSchema.entries`, so the generic
833
+ * `elementCoordinates` walk never yields it. Serialized pack contracts do
834
+ * not carry `native_enum` entries at all (`PostgresContractSerializer`
835
+ * strips them; only the derived `valueSet` survives), so this subtraction
836
+ * currently matches in-memory described contracts only.
837
+ */
838
+ function describedNativeEnumOwnersByTypeName(describedContracts) {
839
+ const owners = /* @__PURE__ */ new Map();
840
+ for (const entry of describedContracts) for (const [namespaceId, ns] of Object.entries(entry.contract.storage.namespaces)) {
841
+ const kindMap = ns.entries["native_enum"];
842
+ if (!isPlainRecord(kindMap)) continue;
843
+ for (const entity of Object.values(kindMap)) {
844
+ if (!PostgresNativeEnum.is(entity)) continue;
845
+ owners.set(coordinateKey({
846
+ namespaceId,
847
+ entityKind: "native_enum",
848
+ entityName: entity.typeName
849
+ }), entry);
850
+ }
851
+ }
852
+ return owners;
853
+ }
854
+ function buildPslDocumentAst(schemaIR, options, foreignKeyExtras, namespaceName) {
781
855
  const { typeMap, defaultMapping, parseRawDefault: rawDefaultParser } = options;
782
856
  const { extraRelationsByTable, crossSpaceFieldNamesByTable } = foreignKeyExtras;
783
857
  const modelNames = buildTopLevelNameMap(Object.keys(schemaIR.tables), toModelName, "model", "table");
784
858
  const modelNameMap = new Map([...modelNames].map(([tableName, result]) => [tableName, result.name]));
785
- const reservedNamedTypeNames = createReservedNamedTypeNames(modelNames);
859
+ const { enumNameMap: bareEnumNameMap, enumBlocks } = buildNativeEnumBlocks(options.enumInfo?.definitions ?? /* @__PURE__ */ new Map(), modelNames);
860
+ const enumNameMap = new Map(bareEnumNameMap);
861
+ if (namespaceName !== void 0) for (const [typeName, pslName] of bareEnumNameMap) enumNameMap.set(`${namespaceName}.${typeName}`, pslName);
862
+ const reservedNamedTypeNames = createReservedNamedTypeNames(modelNames, enumNameMap);
786
863
  const fieldNamesByTable = new Map([...crossSpaceFieldNamesByTable, ...buildFieldNamesByTable(schemaIR.tables)]);
787
864
  const { relationsByTable } = inferRelations(schemaIR.tables, modelNameMap);
788
- const namedTypes = seedNamedTypeRegistry(schemaIR, typeMap, /* @__PURE__ */ new Map(), reservedNamedTypeNames);
865
+ const namedTypes = seedNamedTypeRegistry(schemaIR, typeMap, enumNameMap, reservedNamedTypeNames);
789
866
  const models = [];
790
- for (const table of Object.values(schemaIR.tables)) models.push(buildModel(table, typeMap, /* @__PURE__ */ new Map(), fieldNamesByTable, namedTypes, defaultMapping, rawDefaultParser, [...relationsByTable.get(table.name) ?? [], ...extraRelationsByTable.get(table.name) ?? []]));
867
+ for (const table of Object.values(schemaIR.tables)) models.push(buildModel(table, typeMap, enumNameMap, fieldNamesByTable, namedTypes, defaultMapping, rawDefaultParser, [...relationsByTable.get(table.name) ?? [], ...extraRelationsByTable.get(table.name) ?? []]));
791
868
  const sortedModels = topologicalSort(models, schemaIR.tables, modelNameMap);
792
869
  const namedTypeEntries = [...namedTypes.entriesByKey.values()].sort((a, b) => a.name.localeCompare(b.name));
793
870
  const types = namedTypeEntries.length > 0 ? {
@@ -800,14 +877,69 @@ function buildPslDocumentAst(schemaIR, options, foreignKeyExtras) {
800
877
  sourceId: "<sql-schema-ir>",
801
878
  namespaces: [makePslNamespace({
802
879
  kind: "namespace",
803
- name: UNSPECIFIED_PSL_NAMESPACE_ID,
804
- entries: makePslNamespaceEntries(sortedModels, [], []),
880
+ name: namespaceName ?? UNSPECIFIED_PSL_NAMESPACE_ID,
881
+ entries: makePslNamespaceEntries(sortedModels, [], enumBlocks),
805
882
  span: SYNTHETIC_SPAN
806
883
  })],
807
884
  ...types ? { types } : {},
808
885
  span: SYNTHETIC_SPAN
809
886
  };
810
887
  }
888
+ /**
889
+ * Builds one `native_enum` extension-block AST node per introspected enum
890
+ * definition. Block names go through the shared top-level transform
891
+ * (`toEnumName`, intra-enum collisions throw like model collisions) and are
892
+ * then reserved against the model names — an enum whose PSL name a model
893
+ * already claims gets a numeric suffix, with `@@map` carrying the real type
894
+ * name. Members print as explicit `member = "value"` pairs: the member name
895
+ * is the sanitized value (deduplicated within the block), the JSON-encoded
896
+ * value carries the truth verbatim.
897
+ */
898
+ function buildNativeEnumBlocks(definitions, modelNames) {
899
+ const enumNames = buildTopLevelNameMap([...definitions.keys()].sort(), toEnumName, "enum", "enum type");
900
+ const usedTopLevelNames = new Set(PSL_SCALAR_TYPE_NAMES);
901
+ for (const result of modelNames.values()) usedTopLevelNames.add(result.name);
902
+ const enumNameMap = /* @__PURE__ */ new Map();
903
+ const enumBlocks = [];
904
+ for (const [typeName, result] of enumNames) {
905
+ const name = createUniqueFieldName(result.name, usedTopLevelNames);
906
+ usedTopLevelNames.add(name);
907
+ enumNameMap.set(typeName, name);
908
+ enumBlocks.push(buildNativeEnumBlock(name, typeName, definitions.get(typeName) ?? []));
909
+ }
910
+ return {
911
+ enumNameMap,
912
+ enumBlocks
913
+ };
914
+ }
915
+ function buildNativeEnumBlock(name, typeName, values) {
916
+ const usedMemberNames = /* @__PURE__ */ new Set();
917
+ const parameters = {};
918
+ for (const value of values) {
919
+ const memberName = createUniqueFieldName(toEnumMemberName(value), usedMemberNames);
920
+ usedMemberNames.add(memberName);
921
+ parameters[memberName] = {
922
+ kind: "value",
923
+ raw: JSON.stringify(value),
924
+ span: SYNTHETIC_SPAN
925
+ };
926
+ }
927
+ return {
928
+ kind: "native_enum",
929
+ name,
930
+ parameters,
931
+ blockAttributes: name === typeName ? [] : [{
932
+ name: "map",
933
+ args: [{
934
+ kind: "positional",
935
+ value: `"${escapePslString(typeName)}"`,
936
+ span: SYNTHETIC_SPAN
937
+ }],
938
+ span: SYNTHETIC_SPAN
939
+ }],
940
+ span: SYNTHETIC_SPAN
941
+ };
942
+ }
811
943
  function buildModel(table, typeMap, enumNameMap, fieldNamesByTable, namedTypes, defaultMapping, rawDefaultParser, relationFields) {
812
944
  const { name: modelName, map: mapName } = toModelName(table.name);
813
945
  const fieldNameMap = fieldNamesByTable.get(table.name);
@@ -867,8 +999,17 @@ function buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, nam
867
999
  };
868
1000
  }
869
1001
  let typeName = resolution.pslType;
1002
+ let typeConstructor;
870
1003
  const enumPslName = enumNameMap.get(column.nativeType);
871
- if (enumPslName) typeName = enumPslName;
1004
+ if (enumPslName) {
1005
+ typeName = enumPslName;
1006
+ typeConstructor = {
1007
+ kind: "typeConstructor",
1008
+ path: ["pg", "enum"],
1009
+ args: [positionalArg(enumPslName)],
1010
+ span: SYNTHETIC_SPAN
1011
+ };
1012
+ }
872
1013
  if (resolution.nativeTypeAttribute && !enumPslName) typeName = resolveNamedTypeName(namedTypes, resolution);
873
1014
  const attributes = [];
874
1015
  const isId = isSinglePk && pkColumns.has(column.name);
@@ -889,6 +1030,7 @@ function buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, nam
889
1030
  kind: "field",
890
1031
  name: fieldName,
891
1032
  typeName,
1033
+ ...ifDefined("typeConstructor", typeConstructor),
892
1034
  optional: column.nullable,
893
1035
  list: column.many === true,
894
1036
  attributes,
@@ -1038,9 +1180,10 @@ function buildTopLevelNameMap(sources, normalize, kind, sourceKind) {
1038
1180
  }
1039
1181
  return results;
1040
1182
  }
1041
- function createReservedNamedTypeNames(modelNames) {
1183
+ function createReservedNamedTypeNames(modelNames, enumNameMap) {
1042
1184
  const reservedNames = new Set(PSL_SCALAR_TYPE_NAMES);
1043
1185
  for (const result of modelNames.values()) reservedNames.add(result.name);
1186
+ for (const enumPslName of enumNameMap.values()) reservedNames.add(enumPslName);
1044
1187
  return reservedNames;
1045
1188
  }
1046
1189
  function seedNamedTypeRegistry(schemaIR, typeMap, enumNameMap, reservedNames) {