@prisma-next/adapter-postgres 0.3.0-dev.10 → 0.3.0-dev.113

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 (92) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +64 -2
  3. package/dist/adapter-CWmWEFe1.mjs +361 -0
  4. package/dist/adapter-CWmWEFe1.mjs.map +1 -0
  5. package/dist/adapter.d.mts +23 -0
  6. package/dist/adapter.d.mts.map +1 -0
  7. package/dist/adapter.mjs +3 -0
  8. package/dist/codec-ids-Bsm9c7ns.mjs +29 -0
  9. package/dist/codec-ids-Bsm9c7ns.mjs.map +1 -0
  10. package/dist/codec-types.d.mts +141 -0
  11. package/dist/codec-types.d.mts.map +1 -0
  12. package/dist/codec-types.mjs +3 -0
  13. package/dist/codecs-DgJcyEBR.mjs +254 -0
  14. package/dist/codecs-DgJcyEBR.mjs.map +1 -0
  15. package/dist/column-types.d.mts +110 -0
  16. package/dist/column-types.d.mts.map +1 -0
  17. package/dist/column-types.mjs +180 -0
  18. package/dist/column-types.mjs.map +1 -0
  19. package/dist/control.d.mts +77 -0
  20. package/dist/control.d.mts.map +1 -0
  21. package/dist/control.mjs +773 -0
  22. package/dist/control.mjs.map +1 -0
  23. package/dist/descriptor-meta-l_dv8Nnn.mjs +884 -0
  24. package/dist/descriptor-meta-l_dv8Nnn.mjs.map +1 -0
  25. package/dist/runtime.d.mts +19 -0
  26. package/dist/runtime.d.mts.map +1 -0
  27. package/dist/runtime.mjs +99 -0
  28. package/dist/runtime.mjs.map +1 -0
  29. package/dist/sql-utils-CSfAGEwF.mjs +78 -0
  30. package/dist/sql-utils-CSfAGEwF.mjs.map +1 -0
  31. package/dist/types-aQLL6QVb.d.mts +19 -0
  32. package/dist/types-aQLL6QVb.d.mts.map +1 -0
  33. package/dist/types.d.mts +2 -0
  34. package/dist/types.mjs +1 -0
  35. package/package.json +39 -46
  36. package/src/core/adapter.ts +529 -256
  37. package/src/core/codec-ids.ts +28 -0
  38. package/src/core/codecs.ts +385 -36
  39. package/src/core/control-adapter.ts +404 -179
  40. package/src/core/control-mutation-defaults.ts +335 -0
  41. package/src/core/default-normalizer.ts +138 -0
  42. package/src/core/descriptor-meta.ts +296 -9
  43. package/src/core/enum-control-hooks.ts +733 -0
  44. package/src/core/json-schema-type-expression.ts +131 -0
  45. package/src/core/json-schema-validator.ts +53 -0
  46. package/src/core/sql-utils.ts +111 -0
  47. package/src/core/standard-schema.ts +71 -0
  48. package/src/core/types.ts +5 -3
  49. package/src/exports/codec-types.ts +73 -1
  50. package/src/exports/column-types.ts +233 -9
  51. package/src/exports/control.ts +20 -9
  52. package/src/exports/runtime.ts +76 -19
  53. package/dist/chunk-HD5YISNQ.js +0 -47
  54. package/dist/chunk-HD5YISNQ.js.map +0 -1
  55. package/dist/chunk-J3XSOAM2.js +0 -162
  56. package/dist/chunk-J3XSOAM2.js.map +0 -1
  57. package/dist/chunk-T6S3A6VT.js +0 -301
  58. package/dist/chunk-T6S3A6VT.js.map +0 -1
  59. package/dist/core/adapter.d.ts +0 -19
  60. package/dist/core/adapter.d.ts.map +0 -1
  61. package/dist/core/codecs.d.ts +0 -110
  62. package/dist/core/codecs.d.ts.map +0 -1
  63. package/dist/core/control-adapter.d.ts +0 -33
  64. package/dist/core/control-adapter.d.ts.map +0 -1
  65. package/dist/core/descriptor-meta.d.ts +0 -72
  66. package/dist/core/descriptor-meta.d.ts.map +0 -1
  67. package/dist/core/types.d.ts +0 -16
  68. package/dist/core/types.d.ts.map +0 -1
  69. package/dist/exports/adapter.d.ts +0 -2
  70. package/dist/exports/adapter.d.ts.map +0 -1
  71. package/dist/exports/adapter.js +0 -8
  72. package/dist/exports/adapter.js.map +0 -1
  73. package/dist/exports/codec-types.d.ts +0 -11
  74. package/dist/exports/codec-types.d.ts.map +0 -1
  75. package/dist/exports/codec-types.js +0 -7
  76. package/dist/exports/codec-types.js.map +0 -1
  77. package/dist/exports/column-types.d.ts +0 -17
  78. package/dist/exports/column-types.d.ts.map +0 -1
  79. package/dist/exports/column-types.js +0 -49
  80. package/dist/exports/column-types.js.map +0 -1
  81. package/dist/exports/control.d.ts +0 -8
  82. package/dist/exports/control.d.ts.map +0 -1
  83. package/dist/exports/control.js +0 -279
  84. package/dist/exports/control.js.map +0 -1
  85. package/dist/exports/runtime.d.ts +0 -15
  86. package/dist/exports/runtime.d.ts.map +0 -1
  87. package/dist/exports/runtime.js +0 -20
  88. package/dist/exports/runtime.js.map +0 -1
  89. package/dist/exports/types.d.ts +0 -2
  90. package/dist/exports/types.d.ts.map +0 -1
  91. package/dist/exports/types.js +0 -1
  92. package/dist/exports/types.js.map +0 -1
@@ -0,0 +1,773 @@
1
+ import { i as quoteIdentifier, n as escapeLiteral, r as qualifyName, t as SqlEscapeError } from "./sql-utils-CSfAGEwF.mjs";
2
+ import { n as pgEnumControlHooks, t as postgresAdapterDescriptorMeta } from "./descriptor-meta-l_dv8Nnn.mjs";
3
+ import { ifDefined } from "@prisma-next/utils/defined";
4
+ import { builtinGeneratorRegistryMetadata, resolveBuiltinGeneratedColumnDescriptor } from "@prisma-next/ids";
5
+
6
+ //#region src/core/default-normalizer.ts
7
+ /**
8
+ * Pre-compiled regex patterns for performance.
9
+ * These are compiled once at module load time rather than on each function call.
10
+ */
11
+ const NEXTVAL_PATTERN = /^nextval\s*\(/i;
12
+ const NOW_FUNCTION_PATTERN = /^(now\s*\(\s*\)|CURRENT_TIMESTAMP)$/i;
13
+ const CLOCK_TIMESTAMP_PATTERN = /^clock_timestamp\s*\(\s*\)$/i;
14
+ const TIMESTAMP_CAST_SUFFIX = /::timestamp(?:tz|\s+(?:with|without)\s+time\s+zone)?$/i;
15
+ const TEXT_CAST_SUFFIX = /::text$/i;
16
+ const NOW_LITERAL_PATTERN = /^'now'$/i;
17
+ const UUID_PATTERN = /^gen_random_uuid\s*\(\s*\)$/i;
18
+ const UUID_OSSP_PATTERN = /^uuid_generate_v4\s*\(\s*\)$/i;
19
+ const NULL_PATTERN = /^NULL(?:::.+)?$/i;
20
+ const TRUE_PATTERN = /^true$/i;
21
+ const FALSE_PATTERN = /^false$/i;
22
+ const NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
23
+ const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:"[^"]+"|[\w\s]+)(?:\(\d+\))?)?$/;
24
+ /**
25
+ * Returns the canonical expression for a timestamp default function, or undefined
26
+ * if the expression is not a recognized timestamp default.
27
+ *
28
+ * Keeps now()/CURRENT_TIMESTAMP and clock_timestamp() distinct:
29
+ * - now(), CURRENT_TIMESTAMP, ('now'::text)::timestamp... → 'now()'
30
+ * - clock_timestamp(), clock_timestamp()::timestamptz → 'clock_timestamp()'
31
+ *
32
+ * These are semantically different in Postgres: now() returns the transaction
33
+ * start time (constant within a transaction), while clock_timestamp() returns
34
+ * the actual wall-clock time (can differ across rows in a single INSERT).
35
+ */
36
+ function canonicalizeTimestampDefault(expr) {
37
+ if (NOW_FUNCTION_PATTERN.test(expr)) return "now()";
38
+ if (CLOCK_TIMESTAMP_PATTERN.test(expr)) return "clock_timestamp()";
39
+ if (!TIMESTAMP_CAST_SUFFIX.test(expr)) return void 0;
40
+ let inner = expr.replace(TIMESTAMP_CAST_SUFFIX, "").trim();
41
+ if (inner.startsWith("(") && inner.endsWith(")")) inner = inner.slice(1, -1).trim();
42
+ if (NOW_FUNCTION_PATTERN.test(inner)) return "now()";
43
+ if (CLOCK_TIMESTAMP_PATTERN.test(inner)) return "clock_timestamp()";
44
+ inner = inner.replace(TEXT_CAST_SUFFIX, "").trim();
45
+ if (NOW_LITERAL_PATTERN.test(inner)) return "now()";
46
+ }
47
+ /**
48
+ * Parses a raw Postgres column default expression into a normalized ColumnDefault.
49
+ * This enables semantic comparison between contract defaults and introspected schema defaults.
50
+ *
51
+ * Used by the migration diff layer to normalize raw database defaults during comparison,
52
+ * keeping the introspection layer focused on faithful data capture.
53
+ *
54
+ * @param rawDefault - Raw default expression from information_schema.columns.column_default
55
+ * @param nativeType - Native column type, used for type-aware parsing (bigint tagging, JSON detection)
56
+ * @returns Normalized ColumnDefault or undefined if the expression cannot be parsed
57
+ */
58
+ function parsePostgresDefault(rawDefault, nativeType) {
59
+ const trimmed = rawDefault.trim();
60
+ const normalizedType = nativeType?.toLowerCase();
61
+ const isBigInt = normalizedType === "bigint" || normalizedType === "int8";
62
+ if (NEXTVAL_PATTERN.test(trimmed)) return {
63
+ kind: "function",
64
+ expression: "autoincrement()"
65
+ };
66
+ const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);
67
+ if (canonicalTimestamp) return {
68
+ kind: "function",
69
+ expression: canonicalTimestamp
70
+ };
71
+ if (UUID_PATTERN.test(trimmed)) return {
72
+ kind: "function",
73
+ expression: "gen_random_uuid()"
74
+ };
75
+ if (UUID_OSSP_PATTERN.test(trimmed)) return {
76
+ kind: "function",
77
+ expression: "gen_random_uuid()"
78
+ };
79
+ if (NULL_PATTERN.test(trimmed)) return {
80
+ kind: "literal",
81
+ value: null
82
+ };
83
+ if (TRUE_PATTERN.test(trimmed)) return {
84
+ kind: "literal",
85
+ value: true
86
+ };
87
+ if (FALSE_PATTERN.test(trimmed)) return {
88
+ kind: "literal",
89
+ value: false
90
+ };
91
+ if (NUMERIC_PATTERN.test(trimmed)) {
92
+ if (isBigInt) return {
93
+ kind: "literal",
94
+ value: {
95
+ $type: "bigint",
96
+ value: trimmed
97
+ }
98
+ };
99
+ const num = Number(trimmed);
100
+ if (!Number.isFinite(num)) return void 0;
101
+ return {
102
+ kind: "literal",
103
+ value: num
104
+ };
105
+ }
106
+ const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);
107
+ if (stringMatch?.[1] !== void 0) {
108
+ const unescaped = stringMatch[1].replace(/''/g, "'");
109
+ if (normalizedType === "json" || normalizedType === "jsonb") try {
110
+ return {
111
+ kind: "literal",
112
+ value: JSON.parse(unescaped)
113
+ };
114
+ } catch {}
115
+ return {
116
+ kind: "literal",
117
+ value: unescaped
118
+ };
119
+ }
120
+ return {
121
+ kind: "function",
122
+ expression: trimmed
123
+ };
124
+ }
125
+
126
+ //#endregion
127
+ //#region src/core/control-adapter.ts
128
+ /**
129
+ * Postgres control plane adapter for control-plane operations like introspection.
130
+ * Provides target-specific implementations for control-plane domain actions.
131
+ */
132
+ var PostgresControlAdapter = class {
133
+ familyId = "sql";
134
+ targetId = "postgres";
135
+ /**
136
+ * @deprecated Use targetId instead
137
+ */
138
+ target = "postgres";
139
+ /**
140
+ * Target-specific normalizer for raw Postgres default expressions.
141
+ * Used by schema verification to normalize raw defaults before comparison.
142
+ */
143
+ normalizeDefault = parsePostgresDefault;
144
+ /**
145
+ * Target-specific normalizer for Postgres schema native type names.
146
+ * Used by schema verification to normalize introspected type names
147
+ * before comparison with contract native types.
148
+ */
149
+ normalizeNativeType = normalizeSchemaNativeType;
150
+ /**
151
+ * Introspects a Postgres database schema and returns a raw SqlSchemaIR.
152
+ *
153
+ * This is a pure schema discovery operation that queries the Postgres catalog
154
+ * and returns the schema structure without type mapping or contract enrichment.
155
+ * Type mapping and enrichment are handled separately by enrichment helpers.
156
+ *
157
+ * Uses batched queries to minimize database round trips (7 queries instead of 5T+3).
158
+ *
159
+ * @param driver - ControlDriverInstance<'sql', 'postgres'> instance for executing queries
160
+ * @param contractIR - Optional contract IR for contract-guided introspection (filtering, optimization)
161
+ * @param schema - Schema name to introspect (defaults to 'public')
162
+ * @returns Promise resolving to SqlSchemaIR representing the live database schema
163
+ */
164
+ async introspect(driver, _contractIR, schema = "public") {
165
+ const [tablesResult, columnsResult, pkResult, fkResult, uniqueResult, indexResult, extensionsResult] = await Promise.all([
166
+ driver.query(`SELECT table_name
167
+ FROM information_schema.tables
168
+ WHERE table_schema = $1
169
+ AND table_type = 'BASE TABLE'
170
+ ORDER BY table_name`, [schema]),
171
+ driver.query(`SELECT
172
+ c.table_name,
173
+ column_name,
174
+ data_type,
175
+ udt_name,
176
+ is_nullable,
177
+ character_maximum_length,
178
+ numeric_precision,
179
+ numeric_scale,
180
+ column_default,
181
+ format_type(a.atttypid, a.atttypmod) AS formatted_type
182
+ FROM information_schema.columns c
183
+ JOIN pg_catalog.pg_class cl
184
+ ON cl.relname = c.table_name
185
+ JOIN pg_catalog.pg_namespace ns
186
+ ON ns.nspname = c.table_schema
187
+ AND ns.oid = cl.relnamespace
188
+ JOIN pg_catalog.pg_attribute a
189
+ ON a.attrelid = cl.oid
190
+ AND a.attname = c.column_name
191
+ AND a.attnum > 0
192
+ AND NOT a.attisdropped
193
+ WHERE c.table_schema = $1
194
+ ORDER BY c.table_name, c.ordinal_position`, [schema]),
195
+ driver.query(`SELECT
196
+ tc.table_name,
197
+ tc.constraint_name,
198
+ kcu.column_name,
199
+ kcu.ordinal_position
200
+ FROM information_schema.table_constraints tc
201
+ JOIN information_schema.key_column_usage kcu
202
+ ON tc.constraint_name = kcu.constraint_name
203
+ AND tc.table_schema = kcu.table_schema
204
+ AND tc.table_name = kcu.table_name
205
+ WHERE tc.table_schema = $1
206
+ AND tc.constraint_type = 'PRIMARY KEY'
207
+ ORDER BY tc.table_name, kcu.ordinal_position`, [schema]),
208
+ driver.query(`SELECT
209
+ tc.table_name,
210
+ tc.constraint_name,
211
+ kcu.column_name,
212
+ kcu.ordinal_position,
213
+ ref_ns.nspname AS referenced_table_schema,
214
+ ref_cl.relname AS referenced_table_name,
215
+ ref_att.attname AS referenced_column_name,
216
+ rc.delete_rule,
217
+ rc.update_rule
218
+ FROM information_schema.table_constraints tc
219
+ JOIN information_schema.key_column_usage kcu
220
+ ON tc.constraint_name = kcu.constraint_name
221
+ AND tc.table_schema = kcu.table_schema
222
+ AND tc.table_name = kcu.table_name
223
+ JOIN pg_catalog.pg_constraint pgc
224
+ ON pgc.conname = tc.constraint_name
225
+ AND pgc.connamespace = (
226
+ SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = tc.table_schema
227
+ )
228
+ JOIN pg_catalog.pg_class ref_cl
229
+ ON ref_cl.oid = pgc.confrelid
230
+ JOIN pg_catalog.pg_namespace ref_ns
231
+ ON ref_ns.oid = ref_cl.relnamespace
232
+ JOIN pg_catalog.pg_attribute ref_att
233
+ ON ref_att.attrelid = pgc.confrelid
234
+ AND ref_att.attnum = pgc.confkey[kcu.ordinal_position]
235
+ JOIN information_schema.referential_constraints rc
236
+ ON rc.constraint_name = tc.constraint_name
237
+ AND rc.constraint_schema = tc.table_schema
238
+ WHERE tc.table_schema = $1
239
+ AND tc.constraint_type = 'FOREIGN KEY'
240
+ ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`, [schema]),
241
+ driver.query(`SELECT
242
+ tc.table_name,
243
+ tc.constraint_name,
244
+ kcu.column_name,
245
+ kcu.ordinal_position
246
+ FROM information_schema.table_constraints tc
247
+ JOIN information_schema.key_column_usage kcu
248
+ ON tc.constraint_name = kcu.constraint_name
249
+ AND tc.table_schema = kcu.table_schema
250
+ AND tc.table_name = kcu.table_name
251
+ WHERE tc.table_schema = $1
252
+ AND tc.constraint_type = 'UNIQUE'
253
+ ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`, [schema]),
254
+ driver.query(`SELECT
255
+ i.tablename,
256
+ i.indexname,
257
+ ix.indisunique,
258
+ a.attname,
259
+ a.attnum
260
+ FROM pg_indexes i
261
+ JOIN pg_class ic ON ic.relname = i.indexname
262
+ JOIN pg_namespace ins ON ins.oid = ic.relnamespace AND ins.nspname = $1
263
+ JOIN pg_index ix ON ix.indexrelid = ic.oid
264
+ JOIN pg_class t ON t.oid = ix.indrelid
265
+ JOIN pg_namespace tn ON tn.oid = t.relnamespace AND tn.nspname = $1
266
+ LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) AND a.attnum > 0
267
+ WHERE i.schemaname = $1
268
+ AND NOT EXISTS (
269
+ SELECT 1
270
+ FROM information_schema.table_constraints tc
271
+ WHERE tc.table_schema = $1
272
+ AND tc.table_name = i.tablename
273
+ AND tc.constraint_name = i.indexname
274
+ )
275
+ ORDER BY i.tablename, i.indexname, a.attnum`, [schema]),
276
+ driver.query(`SELECT extname
277
+ FROM pg_extension
278
+ ORDER BY extname`, [])
279
+ ]);
280
+ const columnsByTable = groupBy(columnsResult.rows, "table_name");
281
+ const pksByTable = groupBy(pkResult.rows, "table_name");
282
+ const fksByTable = groupBy(fkResult.rows, "table_name");
283
+ const uniquesByTable = groupBy(uniqueResult.rows, "table_name");
284
+ const indexesByTable = groupBy(indexResult.rows, "tablename");
285
+ const pkConstraintsByTable = /* @__PURE__ */ new Map();
286
+ for (const row of pkResult.rows) {
287
+ let constraints = pkConstraintsByTable.get(row.table_name);
288
+ if (!constraints) {
289
+ constraints = /* @__PURE__ */ new Set();
290
+ pkConstraintsByTable.set(row.table_name, constraints);
291
+ }
292
+ constraints.add(row.constraint_name);
293
+ }
294
+ const tables = {};
295
+ for (const tableRow of tablesResult.rows) {
296
+ const tableName = tableRow.table_name;
297
+ const columns = {};
298
+ for (const colRow of columnsByTable.get(tableName) ?? []) {
299
+ let nativeType = colRow.udt_name;
300
+ const formattedType = colRow.formatted_type ? normalizeFormattedType(colRow.formatted_type, colRow.data_type, colRow.udt_name) : null;
301
+ if (formattedType) nativeType = formattedType;
302
+ else if (colRow.data_type === "character varying" || colRow.data_type === "character") if (colRow.character_maximum_length) nativeType = `${colRow.data_type}(${colRow.character_maximum_length})`;
303
+ else nativeType = colRow.data_type;
304
+ else if (colRow.data_type === "numeric" || colRow.data_type === "decimal") if (colRow.numeric_precision && colRow.numeric_scale !== null) nativeType = `${colRow.data_type}(${colRow.numeric_precision},${colRow.numeric_scale})`;
305
+ else if (colRow.numeric_precision) nativeType = `${colRow.data_type}(${colRow.numeric_precision})`;
306
+ else nativeType = colRow.data_type;
307
+ else nativeType = colRow.udt_name || colRow.data_type;
308
+ columns[colRow.column_name] = {
309
+ name: colRow.column_name,
310
+ nativeType,
311
+ nullable: colRow.is_nullable === "YES",
312
+ ...ifDefined("default", colRow.column_default ?? void 0)
313
+ };
314
+ }
315
+ const pkRows = [...pksByTable.get(tableName) ?? []];
316
+ const primaryKeyColumns = pkRows.sort((a, b) => a.ordinal_position - b.ordinal_position).map((row) => row.column_name);
317
+ const primaryKey = primaryKeyColumns.length > 0 ? {
318
+ columns: primaryKeyColumns,
319
+ ...pkRows[0]?.constraint_name ? { name: pkRows[0].constraint_name } : {}
320
+ } : void 0;
321
+ const foreignKeysMap = /* @__PURE__ */ new Map();
322
+ for (const fkRow of fksByTable.get(tableName) ?? []) {
323
+ const existing = foreignKeysMap.get(fkRow.constraint_name);
324
+ if (existing) {
325
+ existing.columns.push(fkRow.column_name);
326
+ existing.referencedColumns.push(fkRow.referenced_column_name);
327
+ } else foreignKeysMap.set(fkRow.constraint_name, {
328
+ columns: [fkRow.column_name],
329
+ referencedTable: fkRow.referenced_table_name,
330
+ referencedColumns: [fkRow.referenced_column_name],
331
+ name: fkRow.constraint_name,
332
+ deleteRule: fkRow.delete_rule,
333
+ updateRule: fkRow.update_rule
334
+ });
335
+ }
336
+ const foreignKeys = Array.from(foreignKeysMap.values()).map((fk) => ({
337
+ columns: Object.freeze([...fk.columns]),
338
+ referencedTable: fk.referencedTable,
339
+ referencedColumns: Object.freeze([...fk.referencedColumns]),
340
+ name: fk.name,
341
+ ...ifDefined("onDelete", mapReferentialAction(fk.deleteRule)),
342
+ ...ifDefined("onUpdate", mapReferentialAction(fk.updateRule))
343
+ }));
344
+ const pkConstraints = pkConstraintsByTable.get(tableName) ?? /* @__PURE__ */ new Set();
345
+ const uniquesMap = /* @__PURE__ */ new Map();
346
+ for (const uniqueRow of uniquesByTable.get(tableName) ?? []) {
347
+ if (pkConstraints.has(uniqueRow.constraint_name)) continue;
348
+ const existing = uniquesMap.get(uniqueRow.constraint_name);
349
+ if (existing) existing.columns.push(uniqueRow.column_name);
350
+ else uniquesMap.set(uniqueRow.constraint_name, {
351
+ columns: [uniqueRow.column_name],
352
+ name: uniqueRow.constraint_name
353
+ });
354
+ }
355
+ const uniques = Array.from(uniquesMap.values()).map((uq) => ({
356
+ columns: Object.freeze([...uq.columns]),
357
+ name: uq.name
358
+ }));
359
+ const indexesMap = /* @__PURE__ */ new Map();
360
+ for (const idxRow of indexesByTable.get(tableName) ?? []) {
361
+ if (!idxRow.attname) continue;
362
+ const existing = indexesMap.get(idxRow.indexname);
363
+ if (existing) existing.columns.push(idxRow.attname);
364
+ else indexesMap.set(idxRow.indexname, {
365
+ columns: [idxRow.attname],
366
+ name: idxRow.indexname,
367
+ unique: idxRow.indisunique
368
+ });
369
+ }
370
+ const indexes = Array.from(indexesMap.values()).map((idx) => ({
371
+ columns: Object.freeze([...idx.columns]),
372
+ name: idx.name,
373
+ unique: idx.unique
374
+ }));
375
+ tables[tableName] = {
376
+ name: tableName,
377
+ columns,
378
+ ...ifDefined("primaryKey", primaryKey),
379
+ foreignKeys,
380
+ uniques,
381
+ indexes
382
+ };
383
+ }
384
+ const dependencies = extensionsResult.rows.map((row) => ({ id: `postgres.extension.${row.extname}` }));
385
+ const storageTypes = await pgEnumControlHooks.introspectTypes?.({
386
+ driver,
387
+ schemaName: schema
388
+ }) ?? {};
389
+ return {
390
+ tables,
391
+ dependencies,
392
+ annotations: { pg: {
393
+ schema,
394
+ version: await this.getPostgresVersion(driver),
395
+ ...ifDefined("storageTypes", Object.keys(storageTypes).length > 0 ? storageTypes : void 0)
396
+ } }
397
+ };
398
+ }
399
+ /**
400
+ * Gets the Postgres version from the database.
401
+ */
402
+ async getPostgresVersion(driver) {
403
+ return ((await driver.query("SELECT version() AS version", [])).rows[0]?.version ?? "").match(/PostgreSQL (\d+\.\d+)/)?.[1] ?? "unknown";
404
+ }
405
+ };
406
+ /**
407
+ * Pre-computed lookup map for simple prefix-based type normalization.
408
+ * Maps short Postgres type names to their canonical SQL names.
409
+ * Using a Map for O(1) lookup instead of multiple startsWith checks.
410
+ */
411
+ const TYPE_PREFIX_MAP = new Map([
412
+ ["varchar", "character varying"],
413
+ ["bpchar", "character"],
414
+ ["varbit", "bit varying"]
415
+ ]);
416
+ /**
417
+ * Normalizes a Postgres schema native type to its canonical form for comparison.
418
+ *
419
+ * Uses a pre-computed lookup map for simple prefix replacements (O(1))
420
+ * and handles complex temporal type normalization separately.
421
+ */
422
+ function normalizeSchemaNativeType(nativeType) {
423
+ const trimmed = nativeType.trim();
424
+ for (const [prefix, replacement] of TYPE_PREFIX_MAP) if (trimmed.startsWith(prefix)) return replacement + trimmed.slice(prefix.length);
425
+ if (trimmed.includes(" with time zone")) {
426
+ if (trimmed.startsWith("timestamp")) return `timestamptz${trimmed.slice(9).replace(" with time zone", "")}`;
427
+ if (trimmed.startsWith("time")) return `timetz${trimmed.slice(4).replace(" with time zone", "")}`;
428
+ }
429
+ if (trimmed.includes(" without time zone")) return trimmed.replace(" without time zone", "");
430
+ return trimmed;
431
+ }
432
+ function normalizeFormattedType(formattedType, dataType, udtName) {
433
+ if (formattedType === "integer") return "int4";
434
+ if (formattedType === "smallint") return "int2";
435
+ if (formattedType === "bigint") return "int8";
436
+ if (formattedType === "real") return "float4";
437
+ if (formattedType === "double precision") return "float8";
438
+ if (formattedType === "boolean") return "bool";
439
+ if (formattedType.startsWith("varchar")) return formattedType.replace("varchar", "character varying");
440
+ if (formattedType.startsWith("bpchar")) return formattedType.replace("bpchar", "character");
441
+ if (formattedType.startsWith("varbit")) return formattedType.replace("varbit", "bit varying");
442
+ if (dataType === "timestamp with time zone" || udtName === "timestamptz") return formattedType.replace("timestamp", "timestamptz").replace(" with time zone", "").trim();
443
+ if (dataType === "timestamp without time zone" || udtName === "timestamp") return formattedType.replace(" without time zone", "").trim();
444
+ if (dataType === "time with time zone" || udtName === "timetz") return formattedType.replace("time", "timetz").replace(" with time zone", "").trim();
445
+ if (dataType === "time without time zone" || udtName === "time") return formattedType.replace(" without time zone", "").trim();
446
+ if (formattedType.startsWith("\"") && formattedType.endsWith("\"")) return formattedType.slice(1, -1);
447
+ return formattedType;
448
+ }
449
+ const PG_REFERENTIAL_ACTION_MAP = {
450
+ "NO ACTION": "noAction",
451
+ RESTRICT: "restrict",
452
+ CASCADE: "cascade",
453
+ "SET NULL": "setNull",
454
+ "SET DEFAULT": "setDefault"
455
+ };
456
+ /**
457
+ * Maps a Postgres referential action rule to the canonical SqlReferentialAction.
458
+ * Returns undefined for 'NO ACTION' (the database default) to keep the IR sparse.
459
+ * Throws for unrecognized rules to prevent silent data loss.
460
+ */
461
+ function mapReferentialAction(rule) {
462
+ const mapped = PG_REFERENTIAL_ACTION_MAP[rule];
463
+ if (mapped === void 0) throw new Error(`Unknown PostgreSQL referential action rule: "${rule}". Expected one of: NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT.`);
464
+ if (mapped === "noAction") return void 0;
465
+ return mapped;
466
+ }
467
+ /**
468
+ * Groups an array of objects by a specified key.
469
+ * Returns a Map for O(1) lookup by group key.
470
+ */
471
+ function groupBy(items, key) {
472
+ const map = /* @__PURE__ */ new Map();
473
+ for (const item of items) {
474
+ const groupKey = item[key];
475
+ let group = map.get(groupKey);
476
+ if (!group) {
477
+ group = [];
478
+ map.set(groupKey, group);
479
+ }
480
+ group.push(item);
481
+ }
482
+ return map;
483
+ }
484
+
485
+ //#endregion
486
+ //#region src/core/control-mutation-defaults.ts
487
+ function invalidArgumentDiagnostic(input) {
488
+ return {
489
+ ok: false,
490
+ diagnostic: {
491
+ code: "PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT",
492
+ message: input.message,
493
+ sourceId: input.context.sourceId,
494
+ span: input.span
495
+ }
496
+ };
497
+ }
498
+ function executionGenerator(id, params) {
499
+ return {
500
+ ok: true,
501
+ value: {
502
+ kind: "execution",
503
+ generated: {
504
+ kind: "generator",
505
+ id,
506
+ ...params ? { params } : {}
507
+ }
508
+ }
509
+ };
510
+ }
511
+ function expectNoArgs(input) {
512
+ if (input.call.args.length === 0) return;
513
+ return invalidArgumentDiagnostic({
514
+ context: input.context,
515
+ span: input.call.span,
516
+ message: `Default function "${input.call.name}" does not accept arguments. Use ${input.usage}.`
517
+ });
518
+ }
519
+ function parseIntegerArgument(raw) {
520
+ const trimmed = raw.trim();
521
+ if (!/^-?\d+$/.test(trimmed)) return;
522
+ const value = Number(trimmed);
523
+ if (!Number.isInteger(value)) return;
524
+ return value;
525
+ }
526
+ function parseStringLiteral(raw) {
527
+ const match = raw.trim().match(/^(['"])(.*)\1$/s);
528
+ if (!match) return;
529
+ return match[2] ?? "";
530
+ }
531
+ function lowerAutoincrement(input) {
532
+ const maybeNoArgs = expectNoArgs({
533
+ call: input.call,
534
+ context: input.context,
535
+ usage: "`autoincrement()`"
536
+ });
537
+ if (maybeNoArgs) return maybeNoArgs;
538
+ return {
539
+ ok: true,
540
+ value: {
541
+ kind: "storage",
542
+ defaultValue: {
543
+ kind: "function",
544
+ expression: "autoincrement()"
545
+ }
546
+ }
547
+ };
548
+ }
549
+ function lowerNow(input) {
550
+ const maybeNoArgs = expectNoArgs({
551
+ call: input.call,
552
+ context: input.context,
553
+ usage: "`now()`"
554
+ });
555
+ if (maybeNoArgs) return maybeNoArgs;
556
+ return {
557
+ ok: true,
558
+ value: {
559
+ kind: "storage",
560
+ defaultValue: {
561
+ kind: "function",
562
+ expression: "now()"
563
+ }
564
+ }
565
+ };
566
+ }
567
+ function lowerUuid(input) {
568
+ if (input.call.args.length === 0) return executionGenerator("uuidv4");
569
+ if (input.call.args.length !== 1) return invalidArgumentDiagnostic({
570
+ context: input.context,
571
+ span: input.call.span,
572
+ message: "Default function \"uuid\" accepts at most one version argument: `uuid()`, `uuid(4)`, or `uuid(7)`."
573
+ });
574
+ const version = parseIntegerArgument(input.call.args[0]?.raw ?? "");
575
+ if (version === 4) return executionGenerator("uuidv4");
576
+ if (version === 7) return executionGenerator("uuidv7");
577
+ return invalidArgumentDiagnostic({
578
+ context: input.context,
579
+ span: input.call.args[0]?.span ?? input.call.span,
580
+ message: "Default function \"uuid\" supports only `uuid()`, `uuid(4)`, or `uuid(7)` in SQL PSL provider v1."
581
+ });
582
+ }
583
+ function lowerCuid(input) {
584
+ if (input.call.args.length === 0) return {
585
+ ok: false,
586
+ diagnostic: {
587
+ code: "PSL_UNKNOWN_DEFAULT_FUNCTION",
588
+ message: "Default function \"cuid()\" is not supported in SQL PSL provider v1. Use `cuid(2)` instead.",
589
+ sourceId: input.context.sourceId,
590
+ span: input.call.span
591
+ }
592
+ };
593
+ if (input.call.args.length !== 1) return invalidArgumentDiagnostic({
594
+ context: input.context,
595
+ span: input.call.span,
596
+ message: "Default function \"cuid\" accepts exactly one version argument: `cuid(2)`."
597
+ });
598
+ if (parseIntegerArgument(input.call.args[0]?.raw ?? "") === 2) return executionGenerator("cuid2");
599
+ return invalidArgumentDiagnostic({
600
+ context: input.context,
601
+ span: input.call.args[0]?.span ?? input.call.span,
602
+ message: "Default function \"cuid\" supports only `cuid(2)` in SQL PSL provider v1."
603
+ });
604
+ }
605
+ function lowerUlid(input) {
606
+ const maybeNoArgs = expectNoArgs({
607
+ call: input.call,
608
+ context: input.context,
609
+ usage: "`ulid()`"
610
+ });
611
+ if (maybeNoArgs) return maybeNoArgs;
612
+ return executionGenerator("ulid");
613
+ }
614
+ function lowerNanoid(input) {
615
+ if (input.call.args.length === 0) return executionGenerator("nanoid");
616
+ if (input.call.args.length !== 1) return invalidArgumentDiagnostic({
617
+ context: input.context,
618
+ span: input.call.span,
619
+ message: "Default function \"nanoid\" accepts at most one size argument: `nanoid()` or `nanoid(<2-255>)`."
620
+ });
621
+ const size = parseIntegerArgument(input.call.args[0]?.raw ?? "");
622
+ if (size !== void 0 && size >= 2 && size <= 255) return executionGenerator("nanoid", { size });
623
+ return invalidArgumentDiagnostic({
624
+ context: input.context,
625
+ span: input.call.args[0]?.span ?? input.call.span,
626
+ message: "Default function \"nanoid\" size argument must be an integer between 2 and 255."
627
+ });
628
+ }
629
+ function lowerDbgenerated(input) {
630
+ if (input.call.args.length !== 1) return invalidArgumentDiagnostic({
631
+ context: input.context,
632
+ span: input.call.span,
633
+ message: "Default function \"dbgenerated\" requires exactly one string argument: `dbgenerated(\"...\")`."
634
+ });
635
+ const rawExpression = parseStringLiteral(input.call.args[0]?.raw ?? "");
636
+ if (rawExpression === void 0) return invalidArgumentDiagnostic({
637
+ context: input.context,
638
+ span: input.call.args[0]?.span ?? input.call.span,
639
+ message: "Default function \"dbgenerated\" argument must be a string literal."
640
+ });
641
+ if (rawExpression.trim().length === 0) return invalidArgumentDiagnostic({
642
+ context: input.context,
643
+ span: input.call.args[0]?.span ?? input.call.span,
644
+ message: "Default function \"dbgenerated\" argument cannot be empty."
645
+ });
646
+ return {
647
+ ok: true,
648
+ value: {
649
+ kind: "storage",
650
+ defaultValue: {
651
+ kind: "function",
652
+ expression: rawExpression
653
+ }
654
+ }
655
+ };
656
+ }
657
+ const postgresDefaultFunctionRegistryEntries = [
658
+ ["autoincrement", {
659
+ lower: lowerAutoincrement,
660
+ usageSignatures: ["autoincrement()"]
661
+ }],
662
+ ["now", {
663
+ lower: lowerNow,
664
+ usageSignatures: ["now()"]
665
+ }],
666
+ ["uuid", {
667
+ lower: lowerUuid,
668
+ usageSignatures: [
669
+ "uuid()",
670
+ "uuid(4)",
671
+ "uuid(7)"
672
+ ]
673
+ }],
674
+ ["cuid", {
675
+ lower: lowerCuid,
676
+ usageSignatures: ["cuid(2)"]
677
+ }],
678
+ ["ulid", {
679
+ lower: lowerUlid,
680
+ usageSignatures: ["ulid()"]
681
+ }],
682
+ ["nanoid", {
683
+ lower: lowerNanoid,
684
+ usageSignatures: ["nanoid()", "nanoid(<2-255>)"]
685
+ }],
686
+ ["dbgenerated", {
687
+ lower: lowerDbgenerated,
688
+ usageSignatures: ["dbgenerated(\"...\")"]
689
+ }]
690
+ ];
691
+ const postgresPslScalarTypeDescriptors = new Map([
692
+ ["String", {
693
+ codecId: "pg/text@1",
694
+ nativeType: "text"
695
+ }],
696
+ ["Boolean", {
697
+ codecId: "pg/bool@1",
698
+ nativeType: "bool"
699
+ }],
700
+ ["Int", {
701
+ codecId: "pg/int4@1",
702
+ nativeType: "int4"
703
+ }],
704
+ ["BigInt", {
705
+ codecId: "pg/int8@1",
706
+ nativeType: "int8"
707
+ }],
708
+ ["Float", {
709
+ codecId: "pg/float8@1",
710
+ nativeType: "float8"
711
+ }],
712
+ ["Decimal", {
713
+ codecId: "pg/numeric@1",
714
+ nativeType: "numeric"
715
+ }],
716
+ ["DateTime", {
717
+ codecId: "pg/timestamptz@1",
718
+ nativeType: "timestamptz"
719
+ }],
720
+ ["Json", {
721
+ codecId: "pg/jsonb@1",
722
+ nativeType: "jsonb"
723
+ }],
724
+ ["Bytes", {
725
+ codecId: "pg/bytea@1",
726
+ nativeType: "bytea"
727
+ }]
728
+ ]);
729
+ function createPostgresDefaultFunctionRegistry() {
730
+ return new Map(postgresDefaultFunctionRegistryEntries);
731
+ }
732
+ function createPostgresMutationDefaultGeneratorDescriptors() {
733
+ return builtinGeneratorRegistryMetadata.map(({ id, applicableCodecIds }) => ({
734
+ id,
735
+ applicableCodecIds,
736
+ resolveGeneratedColumnDescriptor: ({ generated }) => {
737
+ if (generated.kind !== "generator" || generated.id !== id) return;
738
+ const descriptor = resolveBuiltinGeneratedColumnDescriptor({
739
+ id,
740
+ ...generated.params ? { params: generated.params } : {}
741
+ });
742
+ return {
743
+ codecId: descriptor.type.codecId,
744
+ nativeType: descriptor.type.nativeType,
745
+ ...descriptor.type.typeRef ? { typeRef: descriptor.type.typeRef } : {},
746
+ ...descriptor.typeParams ? { typeParams: descriptor.typeParams } : {}
747
+ };
748
+ }
749
+ }));
750
+ }
751
+ function createPostgresPslScalarTypeDescriptors() {
752
+ return new Map(postgresPslScalarTypeDescriptors);
753
+ }
754
+
755
+ //#endregion
756
+ //#region src/exports/control.ts
757
+ const postgresAdapterDescriptor = {
758
+ ...postgresAdapterDescriptorMeta,
759
+ operationSignatures: () => [],
760
+ pslTypeDescriptors: () => ({ scalarTypeDescriptors: createPostgresPslScalarTypeDescriptors() }),
761
+ controlMutationDefaults: () => ({
762
+ defaultFunctionRegistry: createPostgresDefaultFunctionRegistry(),
763
+ generatorDescriptors: createPostgresMutationDefaultGeneratorDescriptors()
764
+ }),
765
+ create() {
766
+ return new PostgresControlAdapter();
767
+ }
768
+ };
769
+ var control_default = postgresAdapterDescriptor;
770
+
771
+ //#endregion
772
+ export { SqlEscapeError, control_default as default, escapeLiteral, normalizeSchemaNativeType, parsePostgresDefault, qualifyName, quoteIdentifier };
773
+ //# sourceMappingURL=control.mjs.map