@prisma-next/target-postgres 0.13.0-dev.1 → 0.13.0-dev.11

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 (44) hide show
  1. package/dist/control.d.mts.map +1 -1
  2. package/dist/control.mjs +4 -4
  3. package/dist/control.mjs.map +1 -1
  4. package/dist/{enum-planning-BCyvlFHk.mjs → enum-planning-DTMrPLkN.mjs} +0 -0
  5. package/dist/enum-planning-DTMrPLkN.mjs.map +1 -0
  6. package/dist/enum-planning.d.mts +13 -7
  7. package/dist/enum-planning.d.mts.map +1 -1
  8. package/dist/enum-planning.mjs +2 -2
  9. package/dist/{issue-planner-Br0pt1Ea.mjs → issue-planner-B0A7RFN2.mjs} +5 -5
  10. package/dist/{issue-planner-Br0pt1Ea.mjs.map → issue-planner-B0A7RFN2.mjs.map} +1 -1
  11. package/dist/issue-planner.mjs +1 -1
  12. package/dist/migration.mjs +2 -2
  13. package/dist/{op-factory-call-D2aAUhmS.mjs → op-factory-call-Clp7Zr1z.mjs} +2 -2
  14. package/dist/{op-factory-call-D2aAUhmS.mjs.map → op-factory-call-Clp7Zr1z.mjs.map} +1 -1
  15. package/dist/op-factory-call.mjs +1 -1
  16. package/dist/{planner-CAYPJObw.mjs → planner-DID7RZCQ.mjs} +5 -5
  17. package/dist/{planner-CAYPJObw.mjs.map → planner-DID7RZCQ.mjs.map} +1 -1
  18. package/dist/{planner-produced-postgres-migration-NSEhWL0L.mjs → planner-produced-postgres-migration-B8gZBPOR.mjs} +2 -2
  19. package/dist/{planner-produced-postgres-migration-NSEhWL0L.mjs.map → planner-produced-postgres-migration-B8gZBPOR.mjs.map} +1 -1
  20. package/dist/planner-produced-postgres-migration.mjs +1 -1
  21. package/dist/{planner-sql-checks-DAdhnI2c.mjs → planner-sql-checks-DRD5E8A1.mjs} +2 -2
  22. package/dist/{planner-sql-checks-DAdhnI2c.mjs.map → planner-sql-checks-DRD5E8A1.mjs.map} +1 -1
  23. package/dist/planner-sql-checks.mjs +1 -1
  24. package/dist/planner.mjs +1 -1
  25. package/dist/{postgres-contract-serializer-DYTyXjPf.mjs → postgres-contract-serializer-DCg7YaP3.mjs} +12 -5
  26. package/dist/postgres-contract-serializer-DCg7YaP3.mjs.map +1 -0
  27. package/dist/{postgres-migration-COore9Mz.mjs → postgres-migration-BCQEjFHK.mjs} +2 -2
  28. package/dist/{postgres-migration-COore9Mz.mjs.map → postgres-migration-BCQEjFHK.mjs.map} +1 -1
  29. package/dist/{postgres-schema-BuxCxbvB.mjs → postgres-schema-BVTA2QH7.mjs} +17 -6
  30. package/dist/postgres-schema-BVTA2QH7.mjs.map +1 -0
  31. package/dist/runtime.d.mts.map +1 -1
  32. package/dist/runtime.mjs +1 -1
  33. package/dist/types.d.mts +3 -1
  34. package/dist/types.d.mts.map +1 -1
  35. package/dist/types.mjs +1 -1
  36. package/package.json +17 -17
  37. package/src/core/migrations/enum-planning.ts +33 -29
  38. package/src/core/postgres-contract-serializer.ts +15 -1
  39. package/src/core/postgres-schema.ts +35 -16
  40. package/src/exports/control.ts +9 -16
  41. package/src/exports/enum-planning.ts +0 -1
  42. package/dist/enum-planning-BCyvlFHk.mjs.map +0 -1
  43. package/dist/postgres-contract-serializer-DYTyXjPf.mjs.map +0 -1
  44. package/dist/postgres-schema-BuxCxbvB.mjs.map +0 -1
@@ -14,17 +14,25 @@ import { isPostgresSchema } from '../postgres-schema';
14
14
 
15
15
  /**
16
16
  * Codec-typed enum entry shape stored under
17
- * `schema.annotations.pg.storageTypes[(schemaName, nativeType)]`.
17
+ * `schema.annotations.pg.enumTypes[schemaName][nativeType]`.
18
18
  */
19
19
  interface PgStorageTypeEntry {
20
20
  readonly codecId?: string;
21
21
  readonly typeParams?: { readonly values?: unknown };
22
22
  }
23
23
 
24
+ /**
25
+ * Live enum types keyed by `(schemaName, nativeType)` as a nested map, so two
26
+ * schemas sharing a native enum name stay distinct without packing the pair
27
+ * into a string. This is the same `(namespace, entityName)` coordinate the
28
+ * contract side addresses entities by.
29
+ */
30
+ type PgEnumTypesMap = Readonly<Record<string, Readonly<Record<string, PgStorageTypeEntry>>>>;
31
+
24
32
  /** Postgres-specific subtree on family `SqlSchemaIR.annotations`. */
25
33
  export interface PostgresSchemaIrAnnotations {
26
34
  readonly schema?: string;
27
- readonly storageTypes?: Readonly<Record<string, PgStorageTypeEntry>>;
35
+ readonly enumTypes?: PgEnumTypesMap;
28
36
  }
29
37
 
30
38
  function readOptionalString(value: unknown): string | undefined {
@@ -50,20 +58,27 @@ function readPgStorageTypeEntry(value: unknown): PgStorageTypeEntry | undefined
50
58
  };
51
59
  }
52
60
 
53
- function readPgStorageTypesMap(
54
- value: unknown,
55
- ): Readonly<Record<string, PgStorageTypeEntry>> | undefined {
61
+ function readPgEnumTypesMap(value: unknown): PgEnumTypesMap | undefined {
56
62
  if (value === null || typeof value !== 'object' || Array.isArray(value)) {
57
63
  return undefined;
58
64
  }
59
- const entries: Record<string, PgStorageTypeEntry> = {};
60
- for (const [key, entryValue] of Object.entries(value)) {
61
- const entry = readPgStorageTypeEntry(entryValue);
62
- if (entry !== undefined) {
63
- entries[key] = entry;
65
+ const bySchema: Record<string, Record<string, PgStorageTypeEntry>> = {};
66
+ for (const [schemaName, byTypeRaw] of Object.entries(value)) {
67
+ if (byTypeRaw === null || typeof byTypeRaw !== 'object' || Array.isArray(byTypeRaw)) {
68
+ continue;
69
+ }
70
+ const byType: Record<string, PgStorageTypeEntry> = {};
71
+ for (const [nativeType, entryValue] of Object.entries(byTypeRaw)) {
72
+ const entry = readPgStorageTypeEntry(entryValue);
73
+ if (entry !== undefined) {
74
+ byType[nativeType] = entry;
75
+ }
76
+ }
77
+ if (Object.keys(byType).length > 0) {
78
+ bySchema[schemaName] = byType;
64
79
  }
65
80
  }
66
- return Object.keys(entries).length > 0 ? entries : undefined;
81
+ return Object.keys(bySchema).length > 0 ? bySchema : undefined;
67
82
  }
68
83
 
69
84
  /**
@@ -78,25 +93,13 @@ export function readPostgresSchemaIrAnnotations(schema: SqlSchemaIR): PostgresSc
78
93
  return {};
79
94
  }
80
95
  const schemaField = readOptionalString(Reflect.get(raw, 'schema'));
81
- const storageTypes = readPgStorageTypesMap(Reflect.get(raw, 'storageTypes'));
96
+ const enumTypes = readPgEnumTypesMap(Reflect.get(raw, 'enumTypes'));
82
97
  return {
83
98
  ...(schemaField !== undefined ? { schema: schemaField } : {}),
84
- ...(storageTypes !== undefined ? { storageTypes } : {}),
99
+ ...(enumTypes !== undefined ? { enumTypes } : {}),
85
100
  };
86
101
  }
87
102
 
88
- /**
89
- * Separator for `(schemaName, nativeType)` keys in introspected
90
- * `schema.annotations.pg.storageTypes`. NUL cannot appear in Postgres
91
- * identifiers, so the pair is unambiguous.
92
- */
93
- export const ENUM_STORAGE_KEY_SEP = '\u0000';
94
-
95
- /** Builds the schema-qualified storageTypes map key for a live Postgres enum. */
96
- export function enumStorageCompoundKey(schemaName: string, nativeType: string): string {
97
- return `${schemaName}${ENUM_STORAGE_KEY_SEP}${nativeType}`;
98
- }
99
-
100
103
  /**
101
104
  * Resolves the live-schema name a namespace's enums are introspected under,
102
105
  * for keying `readExistingEnumValues` lookups. The unbound namespace's
@@ -149,9 +152,10 @@ export type EnumDiff =
149
152
 
150
153
  /**
151
154
  * Reads existing enum values for `(schemaName, nativeType)` from the
152
- * Postgres-introspected `schema.annotations.pg.storageTypes` map.
155
+ * Postgres-introspected `schema.annotations.pg.enumTypes` map, addressed by
156
+ * the `(schema, nativeType)` coordinate.
153
157
  *
154
- * Schema IR's `storageTypes` slots are always codec-typed
158
+ * Schema IR's enum entries are always codec-typed
155
159
  * (`{codecId: PG_ENUM_CODEC_ID, typeParams.values}`): the introspector
156
160
  * writes that shape, and the Contract→Schema IR projector resolves
157
161
  * `PostgresEnumType` instances down to the same codec-typed triple before
@@ -165,8 +169,8 @@ export function readExistingEnumValues(
165
169
  schemaName: string,
166
170
  nativeType: string,
167
171
  ): readonly string[] | null {
168
- const storageTypes = readPostgresSchemaIrAnnotations(schema).storageTypes;
169
- const existing = storageTypes?.[enumStorageCompoundKey(schemaName, nativeType)];
172
+ const enumTypes = readPostgresSchemaIrAnnotations(schema).enumTypes;
173
+ const existing = enumTypes?.[schemaName]?.[nativeType];
170
174
  if (!existing || existing.codecId !== PG_ENUM_CODEC_ID) {
171
175
  return null;
172
176
  }
@@ -112,9 +112,11 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
112
112
  }
113
113
  }
114
114
 
115
+ const valueSetSlot = entries.valueSet;
116
+ const hasValueSets = valueSetSlot !== undefined && Object.keys(valueSetSlot).length > 0;
115
117
  const emptyTables = Object.keys(entries.table).length === 0;
116
118
  const emptyTypes = !typeSlot || Object.keys(typeSlot).length === 0;
117
- if (id === UNBOUND_NAMESPACE_ID && emptyTables && emptyTypes) {
119
+ if (id === UNBOUND_NAMESPACE_ID && emptyTables && emptyTypes && !hasValueSets) {
118
120
  return PostgresSchema.unbound;
119
121
  }
120
122
  return new PostgresSchema({
@@ -122,6 +124,7 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
122
124
  entries: {
123
125
  table: entries.table,
124
126
  type: typeSlot ?? {},
127
+ ...(hasValueSets ? { valueSet: valueSetSlot } : {}),
125
128
  },
126
129
  });
127
130
  }
@@ -174,12 +177,23 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
174
177
  for (const [typeName, ty] of Object.entries(ns.entries.type)) {
175
178
  typeOut[typeName] = this.serializeJsonValue(ty) as JsonObject;
176
179
  }
180
+ const valueSetEntries = ns.entries.valueSet;
181
+ const valueSetOut: Record<string, JsonObject> = {};
182
+ if (valueSetEntries !== undefined) {
183
+ for (const [valueSetName, valueSet] of Object.entries(valueSetEntries)) {
184
+ valueSetOut[valueSetName] = blindCast<
185
+ JsonObject,
186
+ 'serializeJsonValue round-trips the value-set node through JSON, yielding a JsonObject'
187
+ >(this.serializeJsonValue(valueSet));
188
+ }
189
+ }
177
190
  return {
178
191
  id: ns.id,
179
192
  kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',
180
193
  entries: {
181
194
  table: tablesOut,
182
195
  type: typeOut,
196
+ ...(Object.keys(valueSetOut).length > 0 ? { valueSet: valueSetOut } : {}),
183
197
  },
184
198
  };
185
199
  }
@@ -9,6 +9,8 @@ import {
9
9
  type SqlStorage,
10
10
  StorageTable,
11
11
  type StorageTableInput,
12
+ StorageValueSet,
13
+ type StorageValueSetInput,
12
14
  } from '@prisma-next/sql-contract/types';
13
15
  import { PostgresEnumType, type PostgresEnumTypeInput } from './postgres-enum-type';
14
16
  import { escapeLiteral } from './sql-utils';
@@ -18,6 +20,7 @@ export interface PostgresSchemaInput {
18
20
  readonly entries: {
19
21
  readonly table: Record<string, StorageTable | StorageTableInput>;
20
22
  readonly type: Record<string, PostgresEnumType | PostgresEnumTypeInput>;
23
+ readonly valueSet?: Record<string, StorageValueSet | StorageValueSetInput>;
21
24
  };
22
25
  }
23
26
 
@@ -50,29 +53,44 @@ export class PostgresSchema extends NamespaceBase {
50
53
  readonly entries: Readonly<{
51
54
  readonly table: Readonly<Record<string, StorageTable>>;
52
55
  readonly type: Readonly<Record<string, PostgresEnumType>>;
56
+ readonly valueSet?: Readonly<Record<string, StorageValueSet>>;
53
57
  }>;
54
58
 
55
59
  constructor(input: PostgresSchemaInput) {
56
60
  super();
57
61
  this.id = input.id;
58
- this.entries = Object.freeze({
59
- table: Object.freeze(
60
- Object.fromEntries(
61
- Object.entries(input.entries.table).map(([k, v]) => [
62
- k,
63
- v instanceof StorageTable ? v : new StorageTable(v as StorageTableInput),
64
- ]),
65
- ),
62
+ const table = Object.freeze(
63
+ Object.fromEntries(
64
+ Object.entries(input.entries.table).map(([k, v]) => [
65
+ k,
66
+ v instanceof StorageTable ? v : new StorageTable(v as StorageTableInput),
67
+ ]),
66
68
  ),
67
- type: Object.freeze(
68
- Object.fromEntries(
69
- Object.entries(input.entries.type).map(([k, v]) => [
70
- k,
71
- v instanceof PostgresEnumType ? v : new PostgresEnumType(v as PostgresEnumTypeInput),
72
- ]),
73
- ),
69
+ );
70
+ const type = Object.freeze(
71
+ Object.fromEntries(
72
+ Object.entries(input.entries.type).map(([k, v]) => [
73
+ k,
74
+ v instanceof PostgresEnumType ? v : new PostgresEnumType(v as PostgresEnumTypeInput),
75
+ ]),
74
76
  ),
75
- });
77
+ );
78
+ const valueSetInput = input.entries.valueSet;
79
+ this.entries =
80
+ valueSetInput !== undefined && Object.keys(valueSetInput).length > 0
81
+ ? Object.freeze({
82
+ table,
83
+ type,
84
+ valueSet: Object.freeze(
85
+ Object.fromEntries(
86
+ Object.entries(valueSetInput).map(([k, v]) => [
87
+ k,
88
+ new StorageValueSet({ kind: 'value-set', values: v.values }),
89
+ ]),
90
+ ),
91
+ ),
92
+ })
93
+ : Object.freeze({ table, type });
76
94
  Object.defineProperty(this, 'kind', {
77
95
  value: 'schema',
78
96
  writable: false,
@@ -213,6 +231,7 @@ export function postgresCreateNamespace(
213
231
  entries: {
214
232
  table: input.entries.table,
215
233
  type: (enumTypes ?? {}) as Record<string, PostgresEnumTypeInput>,
234
+ ...(input.entries.valueSet !== undefined ? { valueSet: input.entries.valueSet } : {}),
216
235
  },
217
236
  };
218
237
  if (input.id === UNBOUND_NAMESPACE_ID) {
@@ -10,10 +10,7 @@ import type {
10
10
  import type { SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
11
11
  import { ifDefined } from '@prisma-next/utils/defined';
12
12
  import { postgresTargetDescriptorMeta } from '../core/descriptor-meta';
13
- import {
14
- enumStorageCompoundKey,
15
- resolveDdlSchemaForNamespaceStorage,
16
- } from '../core/migrations/enum-planning';
13
+ import { resolveDdlSchemaForNamespaceStorage } from '../core/migrations/enum-planning';
17
14
  import { createPostgresMigrationPlanner } from '../core/migrations/planner';
18
15
  import { renderDefaultLiteral } from '../core/migrations/planner-ddl-builders';
19
16
  import type { PostgresPlanTargetDetails } from '../core/migrations/planner-target-details';
@@ -80,18 +77,14 @@ const postgresTargetDescriptor: SqlControlTargetDescriptor<'postgres', PostgresP
80
77
  annotationNamespace: 'pg',
81
78
  ...ifDefined('expandNativeType', expander),
82
79
  renderDefault: postgresRenderDefault,
83
- // Schema-qualify enum annotation keys so the projected "from" IR's
84
- // `storageTypes` match `readExistingEnumValues` on the read side
85
- // (the contract-to-contract `migration plan` path). The DDL-schema
86
- // resolution + compound-key format stay here in the target layer;
87
- // the family projector treats the returned string as opaque.
88
- // `undefined` schema IR ⇒ the unbound coordinate resolves to the
89
- // default `public` landing schema, matching the read-side fallback.
90
- resolveEnumStorageKey: (storage, namespaceId, nativeType) =>
91
- enumStorageCompoundKey(
92
- resolveDdlSchemaForNamespaceStorage(storage, namespaceId, undefined),
93
- nativeType,
94
- ),
80
+ // Map each namespace to the live DDL schema its enums are stored
81
+ // under, so the projected "from" IR nests enums by the same schema
82
+ // `readExistingEnumValues` reads (the contract-to-contract `migration
83
+ // plan` path). `undefined` schema IR the unbound coordinate
84
+ // resolves to the default `public` landing schema, matching the
85
+ // read-side fallback.
86
+ resolveEnumNamespaceSchema: (storage, namespaceId) =>
87
+ resolveDdlSchemaForNamespaceStorage(storage, namespaceId, undefined),
95
88
  });
96
89
  },
97
90
  },
@@ -2,7 +2,6 @@ export {
2
2
  createResolveExistingEnumValues,
3
3
  determineEnumDiff,
4
4
  type EnumDiff,
5
- enumStorageCompoundKey,
6
5
  getDesiredEnumValues,
7
6
  type PostgresSchemaIrAnnotations,
8
7
  readExistingEnumValues,
@@ -1 +0,0 @@
1
- {"version":3,"file":"enum-planning-BCyvlFHk.mjs","names":[],"sources":["../src/core/migrations/enum-planning.ts"],"sourcesContent":["/**\n * Pure planning helpers for Postgres enum types: the diff/rebuild logic\n * that the verifier and planner use to walk `PostgresEnumType` instances\n * natively. Op builders live in `./operations/enums.ts`.\n */\n\nimport { arraysEqual } from '@prisma-next/family-sql/schema-verify';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { PostgresEnumStorageEntry, SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';\nimport { PG_ENUM_CODEC_ID } from '../codec-ids';\nimport type { PostgresEnumType } from '../postgres-enum-type';\nimport { isPostgresSchema } from '../postgres-schema';\n\n/**\n * Codec-typed enum entry shape stored under\n * `schema.annotations.pg.storageTypes[(schemaName, nativeType)]`.\n */\ninterface PgStorageTypeEntry {\n readonly codecId?: string;\n readonly typeParams?: { readonly values?: unknown };\n}\n\n/** Postgres-specific subtree on family `SqlSchemaIR.annotations`. */\nexport interface PostgresSchemaIrAnnotations {\n readonly schema?: string;\n readonly storageTypes?: Readonly<Record<string, PgStorageTypeEntry>>;\n}\n\nfunction readOptionalString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction readPgStorageTypeEntry(value: unknown): PgStorageTypeEntry | undefined {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n const codecId = Reflect.get(value, 'codecId');\n const typeParamsRaw = Reflect.get(value, 'typeParams');\n const typeParams =\n typeParamsRaw !== undefined &&\n typeParamsRaw !== null &&\n typeof typeParamsRaw === 'object' &&\n !Array.isArray(typeParamsRaw)\n ? { values: Reflect.get(typeParamsRaw, 'values') }\n : undefined;\n return {\n ...(typeof codecId === 'string' ? { codecId } : {}),\n ...(typeParams !== undefined ? { typeParams } : {}),\n };\n}\n\nfunction readPgStorageTypesMap(\n value: unknown,\n): Readonly<Record<string, PgStorageTypeEntry>> | undefined {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n const entries: Record<string, PgStorageTypeEntry> = {};\n for (const [key, entryValue] of Object.entries(value)) {\n const entry = readPgStorageTypeEntry(entryValue);\n if (entry !== undefined) {\n entries[key] = entry;\n }\n }\n return Object.keys(entries).length > 0 ? entries : undefined;\n}\n\n/**\n * Reads the Postgres annotation envelope (`schema.annotations.pg`) from\n * family Schema IR. `SqlAnnotations` is an open target-pack extensibility\n * map (`Record<string, unknown>`); this accessor narrows the `pg` slot at\n * runtime so Postgres code can read introspection fields without casts.\n */\nexport function readPostgresSchemaIrAnnotations(schema: SqlSchemaIR): PostgresSchemaIrAnnotations {\n const raw = schema.annotations?.['pg'];\n if (raw === undefined || raw === null || typeof raw !== 'object' || Array.isArray(raw)) {\n return {};\n }\n const schemaField = readOptionalString(Reflect.get(raw, 'schema'));\n const storageTypes = readPgStorageTypesMap(Reflect.get(raw, 'storageTypes'));\n return {\n ...(schemaField !== undefined ? { schema: schemaField } : {}),\n ...(storageTypes !== undefined ? { storageTypes } : {}),\n };\n}\n\n/**\n * Separator for `(schemaName, nativeType)` keys in introspected\n * `schema.annotations.pg.storageTypes`. NUL cannot appear in Postgres\n * identifiers, so the pair is unambiguous.\n */\nexport const ENUM_STORAGE_KEY_SEP = '\\u0000';\n\n/** Builds the schema-qualified storageTypes map key for a live Postgres enum. */\nexport function enumStorageCompoundKey(schemaName: string, nativeType: string): string {\n return `${schemaName}${ENUM_STORAGE_KEY_SEP}${nativeType}`;\n}\n\n/**\n * Resolves the live-schema name a namespace's enums are introspected under,\n * for keying `readExistingEnumValues` lookups. The unbound namespace's\n * `ddlSchemaName` is a planner-emit sentinel (`__unbound__`) that never names a\n * real schema, so for the unbound coordinate we read the *introspected* schema\n * recorded on `annotations.pg.schema` (the live `current_schema()` the adapter\n * walked) — that is the schema the enum's `storageTypes` entry is keyed under.\n * Named namespaces resolve to their own DDL schema, which matches the\n * per-schema introspection key directly.\n */\nexport function resolveDdlSchemaForNamespaceStorage(\n storage: SqlStorage,\n namespaceId: string,\n schemaIr?: SqlSchemaIR,\n): string {\n if (namespaceId === UNBOUND_NAMESPACE_ID) {\n return (schemaIr ? readPostgresSchemaIrAnnotations(schemaIr).schema : undefined) ?? 'public';\n }\n const namespace = storage.namespaces[namespaceId];\n if (namespace && isPostgresSchema(namespace)) {\n return namespace.ddlSchemaName(storage);\n }\n return namespaceId;\n}\n\n/** Contract-scoped bridge for the family verifier's enum value resolver. */\nexport function createResolveExistingEnumValues(\n storage: SqlStorage,\n): (\n schema: SqlSchemaIR,\n enumType: PostgresEnumStorageEntry,\n namespaceId: string,\n) => readonly string[] | null {\n return (schema, enumType, namespaceId) =>\n readExistingEnumValues(\n schema,\n resolveDdlSchemaForNamespaceStorage(storage, namespaceId, schema),\n enumType.nativeType,\n );\n}\n\n/**\n * Categorisation of how an existing enum type's values relate to the\n * desired set in the contract.\n */\nexport type EnumDiff =\n | { readonly kind: 'unchanged' }\n | { readonly kind: 'add_values'; readonly values: readonly string[] }\n | { readonly kind: 'rebuild'; readonly removedValues: readonly string[] };\n\n/**\n * Reads existing enum values for `(schemaName, nativeType)` from the\n * Postgres-introspected `schema.annotations.pg.storageTypes` map.\n *\n * Schema IR's `storageTypes` slots are always codec-typed\n * (`{codecId: PG_ENUM_CODEC_ID, typeParams.values}`): the introspector\n * writes that shape, and the Contract→Schema IR projector resolves\n * `PostgresEnumType` instances down to the same codec-typed triple before\n * they ever land in Schema IR. There is no second on-disk shape to\n * accept here.\n *\n * Returns `null` when no enum entry exists for the given native type.\n */\nexport function readExistingEnumValues(\n schema: SqlSchemaIR,\n schemaName: string,\n nativeType: string,\n): readonly string[] | null {\n const storageTypes = readPostgresSchemaIrAnnotations(schema).storageTypes;\n const existing = storageTypes?.[enumStorageCompoundKey(schemaName, nativeType)];\n if (!existing || existing.codecId !== PG_ENUM_CODEC_ID) {\n return null;\n }\n const enumValues = existing.typeParams?.values;\n if (!Array.isArray(enumValues) || !enumValues.every((v) => typeof v === 'string')) {\n return null;\n }\n return enumValues;\n}\n\n/**\n * Determines what changes are needed to transform existing enum values to\n * desired values.\n *\n * Postgres enums can only have values added (not removed or reordered)\n * without a full type rebuild involving temp type creation and column\n * migration; `'rebuild'` covers the value-removal and reorder cases.\n */\nexport function determineEnumDiff(\n existing: readonly string[],\n desired: readonly string[],\n): EnumDiff {\n if (arraysEqual(existing, desired)) {\n return { kind: 'unchanged' };\n }\n const existingSet = new Set(existing);\n const desiredSet = new Set(desired);\n const missingValues = desired.filter((value) => !existingSet.has(value));\n const removedValues = existing.filter((value) => !desiredSet.has(value));\n const orderMismatch =\n missingValues.length === 0 && removedValues.length === 0 && !arraysEqual(existing, desired);\n if (removedValues.length > 0 || orderMismatch) {\n return { kind: 'rebuild', removedValues };\n }\n return { kind: 'add_values', values: missingValues };\n}\n\n/**\n * Convenience accessor — returns the enum's desired values from a\n * `PostgresEnumType` IR instance.\n */\nexport function getDesiredEnumValues(typeInstance: PostgresEnumType): readonly string[] {\n return typeInstance.values;\n}\n"],"mappings":";;;;;;;;;;AA6BA,SAAS,mBAAmB,OAAoC;CAC9D,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;AAEA,SAAS,uBAAuB,OAAgD;CAC9E,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GACpE;CAEF,MAAM,UAAU,QAAQ,IAAI,OAAO,SAAS;CAC5C,MAAM,gBAAgB,QAAQ,IAAI,OAAO,YAAY;CACrD,MAAM,aACJ,kBAAkB,KAAA,KAClB,kBAAkB,QAClB,OAAO,kBAAkB,YACzB,CAAC,MAAM,QAAQ,aAAa,IACxB,EAAE,QAAQ,QAAQ,IAAI,eAAe,QAAQ,EAAE,IAC/C,KAAA;CACN,OAAO;EACL,GAAI,OAAO,YAAY,WAAW,EAAE,QAAQ,IAAI,CAAC;EACjD,GAAI,eAAe,KAAA,IAAY,EAAE,WAAW,IAAI,CAAC;CACnD;AACF;AAEA,SAAS,sBACP,OAC0D;CAC1D,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GACpE;CAEF,MAAM,UAA8C,CAAC;CACrD,KAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,KAAK,GAAG;EACrD,MAAM,QAAQ,uBAAuB,UAAU;EAC/C,IAAI,UAAU,KAAA,GACZ,QAAQ,OAAO;CAEnB;CACA,OAAO,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,IAAI,UAAU,KAAA;AACrD;;;;;;;AAQA,SAAgB,gCAAgC,QAAkD;CAChG,MAAM,MAAM,OAAO,cAAc;CACjC,IAAI,QAAQ,KAAA,KAAa,QAAQ,QAAQ,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GACnF,OAAO,CAAC;CAEV,MAAM,cAAc,mBAAmB,QAAQ,IAAI,KAAK,QAAQ,CAAC;CACjE,MAAM,eAAe,sBAAsB,QAAQ,IAAI,KAAK,cAAc,CAAC;CAC3E,OAAO;EACL,GAAI,gBAAgB,KAAA,IAAY,EAAE,QAAQ,YAAY,IAAI,CAAC;EAC3D,GAAI,iBAAiB,KAAA,IAAY,EAAE,aAAa,IAAI,CAAC;CACvD;AACF;;AAUA,SAAgB,uBAAuB,YAAoB,YAA4B;CACrF,OAAO,GAAG,cAAoC;AAChD;;;;;;;;;;;AAYA,SAAgB,oCACd,SACA,aACA,UACQ;CACR,IAAI,gBAAgB,sBAClB,QAAQ,WAAW,gCAAgC,QAAQ,CAAC,CAAC,SAAS,KAAA,MAAc;CAEtF,MAAM,YAAY,QAAQ,WAAW;CACrC,IAAI,aAAa,iBAAiB,SAAS,GACzC,OAAO,UAAU,cAAc,OAAO;CAExC,OAAO;AACT;;AAGA,SAAgB,gCACd,SAK4B;CAC5B,QAAQ,QAAQ,UAAU,gBACxB,uBACE,QACA,oCAAoC,SAAS,aAAa,MAAM,GAChE,SAAS,UACX;AACJ;;;;;;;;;;;;;;AAwBA,SAAgB,uBACd,QACA,YACA,YAC0B;CAE1B,MAAM,WADe,gCAAgC,MAAM,CAAC,CAAC,eAC7B,uBAAuB,YAAY,UAAU;CAC7E,IAAI,CAAC,YAAY,SAAS,YAAA,aACxB,OAAO;CAET,MAAM,aAAa,SAAS,YAAY;CACxC,IAAI,CAAC,MAAM,QAAQ,UAAU,KAAK,CAAC,WAAW,OAAO,MAAM,OAAO,MAAM,QAAQ,GAC9E,OAAO;CAET,OAAO;AACT;;;;;;;;;AAUA,SAAgB,kBACd,UACA,SACU;CACV,IAAI,YAAY,UAAU,OAAO,GAC/B,OAAO,EAAE,MAAM,YAAY;CAE7B,MAAM,cAAc,IAAI,IAAI,QAAQ;CACpC,MAAM,aAAa,IAAI,IAAI,OAAO;CAClC,MAAM,gBAAgB,QAAQ,QAAQ,UAAU,CAAC,YAAY,IAAI,KAAK,CAAC;CACvE,MAAM,gBAAgB,SAAS,QAAQ,UAAU,CAAC,WAAW,IAAI,KAAK,CAAC;CACvE,MAAM,gBACJ,cAAc,WAAW,KAAK,cAAc,WAAW,KAAK,CAAC,YAAY,UAAU,OAAO;CAC5F,IAAI,cAAc,SAAS,KAAK,eAC9B,OAAO;EAAE,MAAM;EAAW;CAAc;CAE1C,OAAO;EAAE,MAAM;EAAc,QAAQ;CAAc;AACrD;;;;;AAMA,SAAgB,qBAAqB,cAAmD;CACtF,OAAO,aAAa;AACtB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"postgres-contract-serializer-DYTyXjPf.mjs","names":["rawRecord"],"sources":["../src/core/postgres-contract-serializer.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport {\n SqlContractSerializerBase,\n type SqlEntityHydrationFactory,\n} from '@prisma-next/family-sql/ir';\nimport {\n type AuthoringEntityContext,\n type AuthoringEntityTypeFactoryOutput,\n type AuthoringEntityTypeNamespace,\n isAuthoringEntityTypeDescriptor,\n} from '@prisma-next/framework-components/authoring';\nimport {\n type Namespace,\n NamespaceBase,\n UNBOUND_NAMESPACE_ID,\n} from '@prisma-next/framework-components/ir';\nimport type { SqlNamespaceTablesInput, SqlStorage } from '@prisma-next/sql-contract/types';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { JsonObject } from '@prisma-next/utils/json';\nimport type { Type } from 'arktype';\nimport { postgresAuthoringEntityTypes } from './authoring';\nimport type { PostgresEnumType } from './postgres-enum-type';\nimport { isPostgresSchema, PostgresSchema } from './postgres-schema';\n\nconst POSTGRES_AUTHORING_CTX: AuthoringEntityContext = {\n family: 'sql',\n target: 'postgres',\n};\n\nfunction isAuthoringEntityTypeFactoryOutput(\n output: unknown,\n): output is AuthoringEntityTypeFactoryOutput<unknown, unknown> {\n return (\n typeof output === 'object' &&\n output !== null &&\n typeof (output as AuthoringEntityTypeFactoryOutput).factory === 'function'\n );\n}\n\n/**\n * Walks a pack's entity-type namespace tree and emits the maps the\n * family base consumes — hydrators and validator-schema fragments, both\n * keyed by the descriptor's `discriminator`.\n */\nfunction collectEntityRegistryContributions(namespace: AuthoringEntityTypeNamespace): {\n readonly entityTypeRegistry: ReadonlyMap<string, SqlEntityHydrationFactory>;\n readonly validatorFragments: ReadonlyMap<string, Type<unknown>>;\n} {\n const entityTypeRegistry = new Map<string, SqlEntityHydrationFactory>();\n const validatorFragments = new Map<string, Type<unknown>>();\n const walk = (node: AuthoringEntityTypeNamespace): void => {\n for (const value of Object.values(node)) {\n if (isAuthoringEntityTypeDescriptor(value)) {\n if (isAuthoringEntityTypeFactoryOutput(value.output)) {\n const { factory } = value.output;\n entityTypeRegistry.set(value.discriminator, (raw) =>\n factory(raw, POSTGRES_AUTHORING_CTX),\n );\n }\n if (value.validatorSchema !== undefined) {\n validatorFragments.set(value.discriminator, value.validatorSchema);\n }\n continue;\n }\n if (typeof value === 'object' && value !== null) {\n walk(value);\n }\n }\n };\n walk(namespace);\n return { entityTypeRegistry, validatorFragments };\n}\n\nexport class PostgresContractSerializer extends SqlContractSerializerBase<Contract<SqlStorage>> {\n constructor() {\n const { entityTypeRegistry, validatorFragments } = collectEntityRegistryContributions(\n postgresAuthoringEntityTypes,\n );\n super(entityTypeRegistry, validatorFragments);\n }\n\n protected override hydrateSqlNamespaceEntry(\n nsId: string,\n raw: Namespace | Record<string, unknown>,\n ): Namespace | SqlNamespaceTablesInput {\n if (raw instanceof NamespaceBase) {\n return raw;\n }\n const hydrated = blindCast<\n SqlNamespaceTablesInput,\n 'super.hydrateSqlNamespaceEntry returns the tables form when raw is not a NamespaceBase'\n >(super.hydrateSqlNamespaceEntry(nsId, raw));\n const { id, entries } = hydrated;\n\n // Extract the postgres-specific `type` slot directly from raw input.\n // The family base handles the `table` slot; the postgres target owns `type`.\n const rawRecord = raw as Record<string, unknown>;\n const rawEntries = rawRecord['entries'];\n let typeSlot: Record<string, PostgresEnumType> | undefined;\n if (rawEntries !== null && typeof rawEntries === 'object' && !Array.isArray(rawEntries)) {\n const rawTypeSlot = (rawEntries as Record<string, unknown>)['type'];\n if (rawTypeSlot !== null && typeof rawTypeSlot === 'object' && !Array.isArray(rawTypeSlot)) {\n const enumFactory = this.entityTypeRegistry.get('postgres-enum');\n typeSlot = Object.fromEntries(\n Object.entries(rawTypeSlot as Record<string, unknown>).map(([name, entry]) => [\n name,\n blindCast<PostgresEnumType, 'postgres-enum factory returns PostgresEnumType'>(\n enumFactory !== undefined ? enumFactory(entry) : entry,\n ),\n ]),\n );\n }\n }\n\n const emptyTables = Object.keys(entries.table).length === 0;\n const emptyTypes = !typeSlot || Object.keys(typeSlot).length === 0;\n if (id === UNBOUND_NAMESPACE_ID && emptyTables && emptyTypes) {\n return PostgresSchema.unbound;\n }\n return new PostgresSchema({\n id,\n entries: {\n table: entries.table,\n type: typeSlot ?? {},\n },\n });\n }\n\n override serializeContract(contract: Contract<SqlStorage>): JsonObject {\n const { storage, ...rest } = contract;\n const namespacesJson: Record<string, JsonObject> = {};\n for (const [nsId, ns] of Object.entries(storage.namespaces)) {\n if (isPostgresSchema(ns)) {\n namespacesJson[nsId] = this.serializePostgresNamespace(ns, ns.id === UNBOUND_NAMESPACE_ID);\n } else {\n const isUnboundSlot = nsId === UNBOUND_NAMESPACE_ID;\n namespacesJson[nsId] = {\n id: nsId,\n kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',\n entries: {\n table: Object.fromEntries(\n Object.entries(ns.entries.table).map(([tableName, table]) => [\n tableName,\n this.serializeJsonValue(table) as JsonObject,\n ]),\n ),\n },\n };\n }\n }\n const storageOut: Record<string, unknown> = {\n storageHash: String(storage.storageHash),\n namespaces: namespacesJson,\n };\n if (storage.types !== undefined) {\n const typesOut: Record<string, JsonObject> = {};\n for (const [name, entry] of Object.entries(storage.types)) {\n typesOut[name] = this.serializeJsonValue(entry) as JsonObject;\n }\n storageOut['types'] = typesOut;\n }\n return {\n ...rest,\n storage: storageOut,\n } as unknown as JsonObject;\n }\n\n private serializePostgresNamespace(ns: PostgresSchema, isUnboundSlot: boolean): JsonObject {\n const tablesOut: Record<string, JsonObject> = {};\n for (const [tableName, table] of Object.entries(ns.entries.table)) {\n tablesOut[tableName] = this.serializeJsonValue(table) as JsonObject;\n }\n const typeOut: Record<string, JsonObject> = {};\n for (const [typeName, ty] of Object.entries(ns.entries.type)) {\n typeOut[typeName] = this.serializeJsonValue(ty) as JsonObject;\n }\n return {\n id: ns.id,\n kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',\n entries: {\n table: tablesOut,\n type: typeOut,\n },\n };\n }\n\n private serializeJsonValue(value: unknown): unknown {\n return JSON.parse(JSON.stringify(value)) as unknown;\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"postgres-schema-BuxCxbvB.mjs","names":[],"sources":["../src/core/postgres-schema.ts"],"sourcesContent":["import {\n freezeNode,\n NamespaceBase,\n UNBOUND_NAMESPACE_ID,\n} from '@prisma-next/framework-components/ir';\nimport {\n type PostgresEnumStorageEntry,\n type SqlNamespaceTablesInput,\n type SqlStorage,\n StorageTable,\n type StorageTableInput,\n} from '@prisma-next/sql-contract/types';\nimport { PostgresEnumType, type PostgresEnumTypeInput } from './postgres-enum-type';\nimport { escapeLiteral } from './sql-utils';\n\nexport interface PostgresSchemaInput {\n readonly id: string;\n readonly entries: {\n readonly table: Record<string, StorageTable | StorageTableInput>;\n readonly type: Record<string, PostgresEnumType | PostgresEnumTypeInput>;\n };\n}\n\n/**\n * Postgres target `Namespace` concretion — a Postgres schema (`CREATE\n * SCHEMA …`). Each Postgres `SqlStorage` carries a\n * `namespaces: Record<NamespaceId, PostgresSchema>` map populated by\n * the Postgres PSL interpreter from `namespace { … }` AST buckets.\n *\n * `entries` holds entity-kind slot maps (`table`, `type`). Qualifier\n * emission is the rendering seam: DDL / SQL emission asks the namespace\n * for its qualifier (`\"<schema>\"`) or for a qualified table name\n * (`\"<schema>\".\"<table>\"`) and consumes the result polymorphically.\n * The unbound singleton below overrides these methods to elide the\n * prefix entirely — call sites stay polymorphic and never branch on\n * `id === UNBOUND_NAMESPACE_ID`.\n */\nexport class PostgresSchema extends NamespaceBase {\n /**\n * Stable singleton reference for the late-bound slot. Materialised\n * lazily below the singleton subclass declaration so the static\n * initialiser sees the subclass before assigning. Consumers always\n * reach for `PostgresSchema.unbound` (or `PostgresUnboundSchema.instance`\n * — same identity).\n */\n static unbound: PostgresUnboundSchema;\n\n declare readonly kind: 'schema';\n readonly id: string;\n readonly entries: Readonly<{\n readonly table: Readonly<Record<string, StorageTable>>;\n readonly type: Readonly<Record<string, PostgresEnumType>>;\n }>;\n\n constructor(input: PostgresSchemaInput) {\n super();\n this.id = input.id;\n this.entries = Object.freeze({\n table: Object.freeze(\n Object.fromEntries(\n Object.entries(input.entries.table).map(([k, v]) => [\n k,\n v instanceof StorageTable ? v : new StorageTable(v as StorageTableInput),\n ]),\n ),\n ),\n type: Object.freeze(\n Object.fromEntries(\n Object.entries(input.entries.type).map(([k, v]) => [\n k,\n v instanceof PostgresEnumType ? v : new PostgresEnumType(v as PostgresEnumTypeInput),\n ]),\n ),\n ),\n });\n Object.defineProperty(this, 'kind', {\n value: 'schema',\n writable: false,\n enumerable: false,\n configurable: true,\n });\n freezeNode(this);\n }\n\n /**\n * The bare schema qualifier as it would appear in a rendered SQL\n * fragment (already quoted). The unbound-schema singleton overrides\n * this to return `''`.\n */\n qualifier(): string {\n return `\"${this.id}\"`;\n }\n\n /**\n * Qualify a table name with the schema prefix\n * (`\"<schema>\".\"<table>\"`). The unbound-schema singleton overrides\n * this to emit just `\"<table>\"` so the resolved DDL is unqualified\n * and `search_path` decides where the object lands at runtime.\n */\n qualifyTable(tableName: string): string {\n return `\"${this.id}\".\"${tableName}\"`;\n }\n\n /**\n * Render a SQL string-literal containing the qualified-name form\n * suitable for `to_regclass(...)` arguments (e.g. `'\"public\".\"user\"'`).\n * The unbound singleton overrides this to elide the schema prefix\n * (`'\"user\"'`) so `search_path` resolves the object at runtime.\n */\n regclassLiteral(name: string): string {\n return `'${escapeLiteral(this.qualifyTable(name))}'`;\n }\n\n /**\n * Render a SQL expression that evaluates to this namespace's schema\n * name at runtime, ready to drop into a `WHERE table_schema = …` /\n * `WHERE n.nspname = …` clause. Named schemas emit a quoted SQL\n * literal (`'public'`); the unbound singleton overrides this to emit\n * `current_schema()` so catalog queries match whichever schema the\n * connection's `search_path` resolved at runtime.\n */\n schemaSqlExpression(): string {\n return `'${escapeLiteral(this.id)}'`;\n }\n\n /**\n * The bare schema name a DDL planner should target when emitting\n * statements that need to identify this namespace in the live\n * database (e.g. `CREATE TABLE \"<ddlSchemaName>\".\"<table>\" …`,\n * catalog filters, planner conflict lookups). Named schemas resolve\n * to their own id. The `PostgresUnboundSchema` singleton inherits\n * this and returns `UNBOUND_NAMESPACE_ID` — callers that dispatch\n * through `qualifyTableName` / `toRegclassLiteral` route through the\n * polymorphic `PostgresUnboundSchema` overrides and produce\n * unqualified (search-path-resolved) output automatically.\n */\n ddlSchemaName(_storage: SqlStorage): string {\n return this.id;\n }\n}\n\n/**\n * Singleton subclass for the reserved sentinel namespace id\n * (`UNBOUND_NAMESPACE_ID`) — the late-bound Postgres slot whose binding\n * the connection's `search_path` resolves at runtime. Overrides\n * qualifier emission to elide the schema prefix; call sites that consume\n * `qualifier()` / `qualifyTable()` get unqualified output without\n * branching on the namespace id.\n *\n * This is the target-side materialization of \"the framework provides\n * affordances; targets implement specifics\": the framework names the\n * sentinel; Postgres decides what late-bound means here (the table\n * name, naked — the schema is supplied by the live connection's\n * `search_path`).\n *\n * `ddlSchemaName` is inherited from `PostgresSchema` and returns\n * `UNBOUND_NAMESPACE_ID`. Downstream helpers (`qualifyTableName`,\n * `toRegclassLiteral`) route through the polymorphic factory and\n * produce unqualified output automatically.\n */\nexport class PostgresUnboundSchema extends PostgresSchema {\n static readonly instance: PostgresUnboundSchema = new PostgresUnboundSchema();\n\n constructor(input?: PostgresSchemaInput) {\n super(input ?? { id: UNBOUND_NAMESPACE_ID, entries: { table: {}, type: {} } });\n }\n\n override qualifier(): string {\n return '';\n }\n\n override qualifyTable(tableName: string): string {\n return `\"${tableName}\"`;\n }\n\n override schemaSqlExpression(): string {\n return 'current_schema()';\n }\n}\n\nPostgresSchema.unbound = PostgresUnboundSchema.instance;\n\n/**\n * Narrow an arbitrary namespace (or `undefined`) to `PostgresSchema`\n * so callers can dispatch to the polymorphic emission methods without\n * branching at the call site. Uses the structural `kind` discriminator\n * (`'schema'`) rather than `instanceof` so the check survives realm /\n * bundle / hot-reload boundaries — matching the rest of the IR's\n * narrowing convention. `PostgresUnboundSchema` passes through because\n * it inherits the same `kind: 'schema'` from `PostgresSchema`.\n */\nexport function isPostgresSchema(ns: unknown): ns is PostgresSchema {\n return (ns as { kind?: unknown } | null | undefined)?.kind === 'schema';\n}\n\n/**\n * Target-supplied `Namespace` factory the Postgres target plumbs\n * through `defineContract({ createNamespace })` and the SQL PSL\n * interpreter. Returns the unbound singleton for the framework\n * sentinel and a fresh `PostgresSchema` for any other coordinate.\n *\n * The factory has no per-call state — every named id deterministically\n * maps to a distinct schema instance — so callers can pass it through\n * by reference and trust the resulting `SqlStorage.namespaces` map to\n * be value-stable for a given input set.\n */\nexport function postgresCreateNamespace(\n input: SqlNamespaceTablesInput,\n enumTypes?: Readonly<Record<string, PostgresEnumStorageEntry>>,\n): PostgresSchema {\n const schemaInput: PostgresSchemaInput = {\n id: input.id,\n entries: {\n table: input.entries.table,\n type: (enumTypes ?? {}) as Record<string, PostgresEnumTypeInput>,\n },\n };\n if (input.id === UNBOUND_NAMESPACE_ID) {\n return new PostgresUnboundSchema(schemaInput);\n }\n return new PostgresSchema(schemaInput);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAqCA,IAAa,iBAAb,cAAoC,cAAc;;;;;;;;CAQhD,OAAO;CAGP;CACA;CAKA,YAAY,OAA4B;EACtC,MAAM;EACN,KAAK,KAAK,MAAM;EAChB,KAAK,UAAU,OAAO,OAAO;GAC3B,OAAO,OAAO,OACZ,OAAO,YACL,OAAO,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAClD,GACA,aAAa,eAAe,IAAI,IAAI,aAAa,CAAsB,CACzE,CAAC,CACH,CACF;GACA,MAAM,OAAO,OACX,OAAO,YACL,OAAO,QAAQ,MAAM,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CACjD,GACA,aAAa,mBAAmB,IAAI,IAAI,iBAAiB,CAA0B,CACrF,CAAC,CACH,CACF;EACF,CAAC;EACD,OAAO,eAAe,MAAM,QAAQ;GAClC,OAAO;GACP,UAAU;GACV,YAAY;GACZ,cAAc;EAChB,CAAC;EACD,WAAW,IAAI;CACjB;;;;;;CAOA,YAAoB;EAClB,OAAO,IAAI,KAAK,GAAG;CACrB;;;;;;;CAQA,aAAa,WAA2B;EACtC,OAAO,IAAI,KAAK,GAAG,KAAK,UAAU;CACpC;;;;;;;CAQA,gBAAgB,MAAsB;EACpC,OAAO,IAAI,cAAc,KAAK,aAAa,IAAI,CAAC,EAAE;CACpD;;;;;;;;;CAUA,sBAA8B;EAC5B,OAAO,IAAI,cAAc,KAAK,EAAE,EAAE;CACpC;;;;;;;;;;;;CAaA,cAAc,UAA8B;EAC1C,OAAO,KAAK;CACd;AACF;;;;;;;;;;;;;;;;;;;;AAqBA,IAAa,wBAAb,MAAa,8BAA8B,eAAe;CACxD,OAAgB,WAAkC,IAAI,sBAAsB;CAE5E,YAAY,OAA6B;EACvC,MAAM,SAAS;GAAE,IAAI;GAAsB,SAAS;IAAE,OAAO,CAAC;IAAG,MAAM,CAAC;GAAE;EAAE,CAAC;CAC/E;CAEA,YAA6B;EAC3B,OAAO;CACT;CAEA,aAAsB,WAA2B;EAC/C,OAAO,IAAI,UAAU;CACvB;CAEA,sBAAuC;EACrC,OAAO;CACT;AACF;AAEA,eAAe,UAAU,sBAAsB;;;;;;;;;;AAW/C,SAAgB,iBAAiB,IAAmC;CAClE,OAAQ,IAA8C,SAAS;AACjE;;;;;;;;;;;;AAaA,SAAgB,wBACd,OACA,WACgB;CAChB,MAAM,cAAmC;EACvC,IAAI,MAAM;EACV,SAAS;GACP,OAAO,MAAM,QAAQ;GACrB,MAAO,aAAa,CAAC;EACvB;CACF;CACA,IAAI,MAAM,OAAO,sBACf,OAAO,IAAI,sBAAsB,WAAW;CAE9C,OAAO,IAAI,eAAe,WAAW;AACvC"}