@prisma-next/adapter-postgres 0.3.0-pr.99.6 → 0.3.0

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