rake-db 2.27.33 → 2.28.1

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.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { isRawSQL, escapeForMigration, ArrayColumn, toSnakeCase, toCamelCase, DomainColumn, toArray, EnumColumn, defaultSchemaConfig, snakeCaseKey, getColumnTypes, parseTableData, emptyObject, escapeString, tableDataMethods, setCurrentColumnName, consumeColumnName, Column, parseTableDataInput, UnknownColumn, setDefaultLanguage, deepCompare, raw, singleQuote, logParamToLogObject, createDbWithAdapter, getImportPath, pathToLog, emptyArray, makeColumnTypes, getStackTrace, colors, makeColumnsByType, RawSql, CustomTypeColumn, assignDbDataToColumn, PostgisGeographyPointColumn, exhaustive, codeToString, addCode, quoteObjectKey, pushTableDataCode, rawSqlToCode, primaryKeyInnerToCode, indexInnerToCode, excludeInnerToCode, constraintInnerToCode, referencesArgsToCode, backtickQuote, TimestampTZColumn, TimestampColumn } from 'pqb';
1
+ import { singleQuote, defaultSchemaConfig, makeColumnTypes, getStackTrace, isRawSQL, escapeForMigration, ArrayColumn, toSnakeCase, toCamelCase, DomainColumn, toArray, EnumColumn, snakeCaseKey, getColumnTypes, parseTableData, emptyObject, escapeString, tableDataMethods, setCurrentColumnName, consumeColumnName, Column, parseTableDataInput, UnknownColumn, setDefaultLanguage, deepCompare, raw, logParamToLogObject, createDbWithAdapter, getImportPath, pathToLog, emptyArray, colors, exhaustive, codeToString, addCode, quoteObjectKey, pushTableDataCode, rawSqlToCode, primaryKeyInnerToCode, indexInnerToCode, excludeInnerToCode, constraintInnerToCode, referencesArgsToCode, backtickQuote, TimestampTZColumn, TimestampColumn, makeColumnsByType, RawSql, CustomTypeColumn, assignDbDataToColumn, PostgisGeographyPointColumn } from 'pqb';
2
2
  import path, { join } from 'path';
3
- import { pathToFileURL, fileURLToPath } from 'node:url';
3
+ import { fileURLToPath, pathToFileURL } from 'node:url';
4
4
  import fs, { mkdir, writeFile, readdir, stat, readFile } from 'fs/promises';
5
5
 
6
6
  class RakeDbError extends Error {
@@ -15,6 +15,177 @@ const clearChanges = () => {
15
15
  const getCurrentChanges = () => currentChanges;
16
16
  const pushChange = (change) => currentChanges.push(change);
17
17
 
18
+ const RAKE_DB_LOCK_KEY = "8582141715823621641";
19
+ const getFirstWordAndRest = (input) => {
20
+ const i = input.search(/(?=[A-Z])|[-_ ]/);
21
+ if (i !== -1) {
22
+ const restStart = input[i] === "-" || input[i] === "_" || input[i] === " " ? i + 1 : i;
23
+ const rest = input.slice(restStart);
24
+ return [input.slice(0, i), rest[0].toLowerCase() + rest.slice(1)];
25
+ } else {
26
+ return [input];
27
+ }
28
+ };
29
+ const getTextAfterRegExp = (input, regex, length) => {
30
+ let i = input.search(regex);
31
+ if (i === -1) return;
32
+ if (input[i] === "-" || input[i] === "_" || input[i] === " ") i++;
33
+ i += length;
34
+ const start = input[i] == "-" || input[i] === "_" || input[i] === " " ? i + 1 : i;
35
+ const text = input.slice(start);
36
+ return text[0].toLowerCase() + text.slice(1);
37
+ };
38
+ const getTextAfterTo = (input) => {
39
+ return getTextAfterRegExp(input, /(To|-to|_to| to)[A-Z-_ ]/, 2);
40
+ };
41
+ const getTextAfterFrom = (input) => {
42
+ return getTextAfterRegExp(input, /(From|-from|_from| from)[A-Z-_ ]/, 4);
43
+ };
44
+ const joinColumns = (columns) => {
45
+ return columns.map((column) => `"${column}"`).join(", ");
46
+ };
47
+ const quoteWithSchema = ({
48
+ schema,
49
+ name
50
+ }) => quoteTable(schema, name);
51
+ const quoteTable = (schema, table) => schema ? `"${schema}"."${table}"` : `"${table}"`;
52
+ const getSchemaAndTableFromName = (name) => {
53
+ const i = name.indexOf(".");
54
+ return i !== -1 ? [name.slice(0, i), name.slice(i + 1)] : [void 0, name];
55
+ };
56
+ const quoteNameFromString = (string) => {
57
+ return quoteTable(...getSchemaAndTableFromName(string));
58
+ };
59
+ const quoteCustomType = (s) => {
60
+ const [schema, type] = getSchemaAndTableFromName(s);
61
+ return schema ? '"' + schema + '".' + type : type;
62
+ };
63
+ const quoteSchemaTable = (arg, excludeCurrentSchema) => {
64
+ return singleQuote(concatSchemaAndName(arg, excludeCurrentSchema));
65
+ };
66
+ const concatSchemaAndName = ({
67
+ schema,
68
+ name
69
+ }, excludeCurrentSchema) => {
70
+ return schema && schema !== excludeCurrentSchema ? `${schema}.${name}` : name;
71
+ };
72
+ const makePopulateEnumQuery = (item) => {
73
+ const [schema, name] = getSchemaAndTableFromName(item.enumName);
74
+ return {
75
+ text: `SELECT unnest(enum_range(NULL::${quoteTable(schema, name)}))::text`,
76
+ then(result) {
77
+ item.options.push(...result.rows.map(([value]) => value));
78
+ }
79
+ };
80
+ };
81
+ const transaction = (adapter, fn) => {
82
+ return adapter.transaction(void 0, fn);
83
+ };
84
+ const queryLock = (trx) => trx.query(`SELECT pg_advisory_xact_lock('${RAKE_DB_LOCK_KEY}')`);
85
+ const getCliParam = (args, name) => {
86
+ if (args) {
87
+ const key = "--" + name;
88
+ for (let i = 0; i < args.length; i += 1) {
89
+ const arg = args[i];
90
+ if (arg === key) return args[i + 1];
91
+ else if (arg.startsWith(key)) return arg.slice(key.length + 1);
92
+ }
93
+ }
94
+ return;
95
+ };
96
+
97
+ const migrationConfigDefaults = {
98
+ schemaConfig: defaultSchemaConfig,
99
+ migrationsPath: path.join("src", "db", "migrations"),
100
+ migrationId: { serial: 4 },
101
+ migrationsTable: "schemaMigrations",
102
+ snakeCase: false,
103
+ commands: {},
104
+ log: true,
105
+ logger: console,
106
+ import() {
107
+ throw new Error(
108
+ "Add `import: (path) => import(path),` setting to `rakeDb` config"
109
+ );
110
+ }
111
+ };
112
+ const ensureMigrationsPath = (config) => {
113
+ if (!config.migrationsPath) {
114
+ config.migrationsPath = migrationConfigDefaults.migrationsPath;
115
+ }
116
+ if (!path.isAbsolute(config.migrationsPath)) {
117
+ config.migrationsPath = path.resolve(
118
+ config.basePath,
119
+ config.migrationsPath
120
+ );
121
+ }
122
+ return config;
123
+ };
124
+ const ensureBasePathAndDbScript = (config, intermediateCallers = 0) => {
125
+ if (config.basePath && config.dbScript) return config;
126
+ let filePath = getStackTrace()?.[3 + intermediateCallers]?.getFileName();
127
+ if (!filePath) {
128
+ throw new Error(
129
+ "Failed to determine path to db script. Please set basePath option of rakeDb"
130
+ );
131
+ }
132
+ if (filePath.startsWith("file://")) {
133
+ filePath = fileURLToPath(filePath);
134
+ }
135
+ const ext = path.extname(filePath);
136
+ if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
137
+ throw new Error(
138
+ `Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
139
+ );
140
+ }
141
+ config.basePath = path.dirname(filePath);
142
+ config.dbScript = path.basename(filePath);
143
+ return config;
144
+ };
145
+ const processRakeDbConfig = (config, args) => {
146
+ const result = { ...migrationConfigDefaults, ...config };
147
+ if (!result.log) {
148
+ delete result.logger;
149
+ }
150
+ ensureBasePathAndDbScript(result, 1);
151
+ ensureMigrationsPath(result);
152
+ if (!result.recurrentPath) {
153
+ result.recurrentPath = path.join(
154
+ result.migrationsPath,
155
+ "recurrent"
156
+ );
157
+ }
158
+ if ("recurrentPath" in result && !path.isAbsolute(result.recurrentPath)) {
159
+ result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
160
+ }
161
+ if ("baseTable" in config && config.baseTable) {
162
+ const { types, snakeCase, language } = config.baseTable.prototype;
163
+ result.columnTypes = types || makeColumnTypes(defaultSchemaConfig);
164
+ if (snakeCase) result.snakeCase = true;
165
+ if (language) result.language = language;
166
+ } else {
167
+ const ct = "columnTypes" in config && config.columnTypes;
168
+ result.columnTypes = (typeof ct === "function" ? ct(
169
+ makeColumnTypes(defaultSchemaConfig)
170
+ ) : ct) || makeColumnTypes(defaultSchemaConfig);
171
+ }
172
+ if (config.migrationId === "serial") {
173
+ result.migrationId = { serial: 4 };
174
+ }
175
+ const transaction = getCliParam(args, "transaction");
176
+ if (transaction) {
177
+ if (transaction !== "single" && transaction !== "per-migration") {
178
+ throw new Error(
179
+ `Unsupported transaction param ${transaction}, expected single or per-migration`
180
+ );
181
+ }
182
+ result.transaction = transaction;
183
+ } else if (!result.transaction) {
184
+ result.transaction = "single";
185
+ }
186
+ return result;
187
+ };
188
+
18
189
  const versionToString = (config, version) => config.migrationId === "timestamp" ? `${version}` : `${version}`.padStart(config.migrationId.serial, "0");
19
190
  const columnTypeToSql = (item) => {
20
191
  return item.data.isOfCustomType ? item instanceof DomainColumn ? quoteNameFromString(item.dataType) : quoteCustomType(item.toSQL()) : item.toSQL();
@@ -386,6 +557,17 @@ const cmpRawSql = (a, b) => {
386
557
  const bValues = JSON.stringify(values);
387
558
  return aSql === bSql && aValues === bValues;
388
559
  };
560
+ const getMigrationsSchemaAndTable = (config) => {
561
+ const [tableSchema, table] = getSchemaAndTableFromName(
562
+ config.migrationsTable
563
+ );
564
+ const schema = tableSchema || (config.schema && config.schema !== "public" ? config.schema : void 0);
565
+ return { schema, table };
566
+ };
567
+ const migrationsSchemaTableSql = (config) => {
568
+ const { schema, table } = getMigrationsSchemaAndTable(config);
569
+ return `${schema ? `"${schema}".` : ""}"${table}"`;
570
+ };
389
571
 
390
572
  const tableMethods = {
391
573
  enum(name) {
@@ -1248,13 +1430,15 @@ const createView = async (migration, up, name, options, sql) => {
1248
1430
  const query = astToQuery(ast);
1249
1431
  await migration.adapter.arrays(interpolateSqlValues(query));
1250
1432
  };
1251
- const makeAst = (up, name, options, sql) => {
1433
+ const makeAst = (up, fullName, options, sql) => {
1252
1434
  if (typeof sql === "string") {
1253
1435
  sql = raw({ raw: sql });
1254
1436
  }
1437
+ const [schema, name] = getSchemaAndTableFromName(fullName);
1255
1438
  return {
1256
1439
  type: "view",
1257
1440
  action: up ? "create" : "drop",
1441
+ schema,
1258
1442
  name,
1259
1443
  shape: {},
1260
1444
  sql,
@@ -1266,12 +1450,13 @@ const astToQuery = (ast) => {
1266
1450
  const values = [];
1267
1451
  const sql = [];
1268
1452
  const { options } = ast;
1453
+ const sqlName = `${ast.schema ? `"${ast.schema}".` : ""}"${ast.name}"`;
1269
1454
  if (ast.action === "create") {
1270
1455
  sql.push("CREATE");
1271
1456
  if (options?.createOrReplace) sql.push("OR REPLACE");
1272
1457
  if (options?.temporary) sql.push("TEMPORARY");
1273
1458
  if (options?.recursive) sql.push("RECURSIVE");
1274
- sql.push(`VIEW "${ast.name}"`);
1459
+ sql.push(`VIEW ${sqlName}`);
1275
1460
  if (options?.columns) {
1276
1461
  sql.push(
1277
1462
  `(${options.columns.map((column) => `"${column}"`).join(", ")})`
@@ -1289,7 +1474,7 @@ const astToQuery = (ast) => {
1289
1474
  } else {
1290
1475
  sql.push("DROP VIEW");
1291
1476
  if (options?.dropIfExists) sql.push(`IF EXISTS`);
1292
- sql.push(`"${ast.name}"`);
1477
+ sql.push(sqlName);
1293
1478
  if (options?.dropMode) sql.push(options.dropMode);
1294
1479
  }
1295
1480
  return {
@@ -1300,7 +1485,6 @@ const astToQuery = (ast) => {
1300
1485
 
1301
1486
  const createMigrationInterface = (tx, up, config) => {
1302
1487
  const adapter = Object.create(tx);
1303
- adapter.schema = adapter.getSchema() ?? "public";
1304
1488
  const { query, arrays } = adapter;
1305
1489
  const log = logParamToLogObject(config.logger || console, config.log);
1306
1490
  adapter.query = (text, values) => {
@@ -2334,7 +2518,7 @@ const renameType = async (migration, from, to, kind) => {
2334
2518
  }
2335
2519
  if (ast.fromSchema !== ast.toSchema) {
2336
2520
  await migration.adapter.query(
2337
- `ALTER ${ast.kind} ${quoteTable(ast.fromSchema, ast.to)} SET SCHEMA "${ast.toSchema ?? migration.adapter.schema}"`
2521
+ `ALTER ${ast.kind} ${quoteTable(ast.fromSchema, ast.to)} SET SCHEMA "${ast.toSchema ?? migration.options.schema ?? "public"}"`
2338
2522
  );
2339
2523
  }
2340
2524
  };
@@ -2408,7 +2592,7 @@ const changeEnumValues = async (migration, enumName, fromValues, toValues) => {
2408
2592
  );
2409
2593
  };
2410
2594
  const recreateEnum = async (migration, { schema, name }, values, errorMessage) => {
2411
- const defaultSchema = migration.adapter.schema;
2595
+ const defaultSchema = migration.options.schema ?? "public";
2412
2596
  const quotedName = quoteTable(schema, name);
2413
2597
  const relKinds = ["r", "m"];
2414
2598
  const { rows: tables } = await migration.adapter.query(
@@ -2639,7 +2823,9 @@ ${arg === "timestamp" || digits !== 4 ? `Set \`migrationId\`: ${arg === "timesta
2639
2823
  };
2640
2824
  const renameMigrationVersionsInDb = async (config, adapter, values) => {
2641
2825
  await adapter.arrays(
2642
- `UPDATE "${config.migrationsTable}" AS t SET version = v.version FROM (VALUES ${values.map(
2826
+ `UPDATE ${migrationsSchemaTableSql(
2827
+ config
2828
+ )} AS t SET version = v.version FROM (VALUES ${values.map(
2643
2829
  ([oldVersion, , newVersion], i) => `('${oldVersion}', $${i + 1}, '${newVersion}')`
2644
2830
  ).join(
2645
2831
  ", "
@@ -2804,13 +2990,44 @@ function getDigitsPrefix(name) {
2804
2990
 
2805
2991
  const saveMigratedVersion = async (db, version, name, config) => {
2806
2992
  await db.silentArrays(
2807
- `INSERT INTO "${config.migrationsTable}"(version, name) VALUES ($1, $2)`,
2993
+ `INSERT INTO ${migrationsSchemaTableSql(
2994
+ config
2995
+ )}(version, name) VALUES ($1, $2)`,
2808
2996
  [version, name]
2809
2997
  );
2810
2998
  };
2999
+ const createMigrationsTable = async (db, config) => {
3000
+ const { schema } = getMigrationsSchemaAndTable(config);
3001
+ if (schema) {
3002
+ try {
3003
+ await db.query(`CREATE SCHEMA "${schema}"`);
3004
+ config.logger?.log(`Created schema ${schema}`);
3005
+ } catch (err) {
3006
+ if (err.code !== "42P06") {
3007
+ throw err;
3008
+ }
3009
+ }
3010
+ }
3011
+ try {
3012
+ await db.query(
3013
+ `CREATE TABLE ${migrationsSchemaTableSql(
3014
+ config
3015
+ )} ( version TEXT NOT NULL, name TEXT NOT NULL )`
3016
+ );
3017
+ config.logger?.log("Created versions table");
3018
+ } catch (err) {
3019
+ if (err.code === "42P07") {
3020
+ config.logger?.log("Versions table exists");
3021
+ } else {
3022
+ throw err;
3023
+ }
3024
+ }
3025
+ };
2811
3026
  const deleteMigratedVersion = async (db, version, name, config) => {
2812
3027
  const res = await db.silentArrays(
2813
- `DELETE FROM "${config.migrationsTable}" WHERE version = $1 AND name = $2`,
3028
+ `DELETE FROM ${migrationsSchemaTableSql(
3029
+ config
3030
+ )} WHERE version = $1 AND name = $2`,
2814
3031
  [version, name]
2815
3032
  );
2816
3033
  if (res.rowCount === 0) {
@@ -2821,7 +3038,7 @@ class NoMigrationsTableError extends Error {
2821
3038
  }
2822
3039
  const getMigratedVersionsMap = async (ctx, adapter, config, renameTo) => {
2823
3040
  try {
2824
- const table = `"${config.migrationsTable}"`;
3041
+ const table = migrationsSchemaTableSql(config);
2825
3042
  const result = await adapter.arrays(
2826
3043
  `SELECT * FROM ${table} ORDER BY version`
2827
3044
  );
@@ -2897,33 +3114,6 @@ async function renameMigrations(config, trx, versions, renameTo) {
2897
3114
  return updatedVersions;
2898
3115
  }
2899
3116
 
2900
- const createMigrationsTable = async (db, config) => {
2901
- const { schema } = db;
2902
- if (schema && schema !== "public") {
2903
- try {
2904
- await db.query(`CREATE SCHEMA "${schema}"`);
2905
- config.logger?.log(`Created schema ${schema}`);
2906
- } catch (err) {
2907
- if (err.code !== "42P06") {
2908
- throw err;
2909
- }
2910
- }
2911
- }
2912
- try {
2913
- await db.query(
2914
- `CREATE TABLE "${config.migrationsTable}" ( version TEXT NOT NULL, name TEXT NOT NULL )`
2915
- );
2916
- config.logger?.log("Created versions table");
2917
- } catch (err) {
2918
- if (err.code === "42P07") {
2919
- config.logger?.log("Versions table exists");
2920
- } else {
2921
- throw err;
2922
- }
2923
- }
2924
- };
2925
-
2926
- const RAKE_DB_LOCK_KEY = "8582141715823621641";
2927
3117
  const transactionIfSingle = (params, fn) => {
2928
3118
  return params.config.transaction === "single" ? transaction(params.adapter, fn) : fn(params.adapter);
2929
3119
  };
@@ -3182,199 +3372,29 @@ const changeMigratedVersion = async (adapter, up, file, config) => {
3182
3372
  );
3183
3373
  };
3184
3374
 
3185
- const getFirstWordAndRest = (input) => {
3186
- const i = input.search(/(?=[A-Z])|[-_ ]/);
3187
- if (i !== -1) {
3188
- const restStart = input[i] === "-" || input[i] === "_" || input[i] === " " ? i + 1 : i;
3189
- const rest = input.slice(restStart);
3190
- return [input.slice(0, i), rest[0].toLowerCase() + rest.slice(1)];
3191
- } else {
3192
- return [input];
3375
+ const ESC = "\x1B";
3376
+ const CSI = `${ESC}[`;
3377
+ const cursorShow = `${CSI}?25h`;
3378
+ const cursorHide = `${CSI}?25l`;
3379
+ const { stdin, stdout } = process;
3380
+ const visibleChars = (s) => s.replace(
3381
+ // eslint-disable-next-line no-control-regex
3382
+ /[\u001B\u009B][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d/#&.:=?%@~_]*)*)?\u0007)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PRZcf-ntqry=><~]))/g,
3383
+ ""
3384
+ ).length;
3385
+ const clear = (text) => {
3386
+ const rows = text.split(/\r?\n/).reduce(
3387
+ (rows2, line) => rows2 + 1 + Math.floor(Math.max(visibleChars(line) - 1, 0) / stdout.columns),
3388
+ 0
3389
+ );
3390
+ let clear2 = "";
3391
+ for (let i = 0; i < rows; i++) {
3392
+ clear2 += `${CSI}2K`;
3393
+ if (i < rows - 1) {
3394
+ clear2 += `${CSI}${i < rows - 1 ? "1A" : "G"}`;
3395
+ }
3193
3396
  }
3194
- };
3195
- const getTextAfterRegExp = (input, regex, length) => {
3196
- let i = input.search(regex);
3197
- if (i === -1) return;
3198
- if (input[i] === "-" || input[i] === "_" || input[i] === " ") i++;
3199
- i += length;
3200
- const start = input[i] == "-" || input[i] === "_" || input[i] === " " ? i + 1 : i;
3201
- const text = input.slice(start);
3202
- return text[0].toLowerCase() + text.slice(1);
3203
- };
3204
- const getTextAfterTo = (input) => {
3205
- return getTextAfterRegExp(input, /(To|-to|_to| to)[A-Z-_ ]/, 2);
3206
- };
3207
- const getTextAfterFrom = (input) => {
3208
- return getTextAfterRegExp(input, /(From|-from|_from| from)[A-Z-_ ]/, 4);
3209
- };
3210
- const joinColumns = (columns) => {
3211
- return columns.map((column) => `"${column}"`).join(", ");
3212
- };
3213
- const quoteWithSchema = ({
3214
- schema,
3215
- name
3216
- }) => quoteTable(schema, name);
3217
- const quoteTable = (schema, table) => schema ? `"${schema}"."${table}"` : `"${table}"`;
3218
- const getSchemaAndTableFromName = (name) => {
3219
- const i = name.indexOf(".");
3220
- return i !== -1 ? [name.slice(0, i), name.slice(i + 1)] : [void 0, name];
3221
- };
3222
- const quoteNameFromString = (string) => {
3223
- return quoteTable(...getSchemaAndTableFromName(string));
3224
- };
3225
- const quoteCustomType = (s) => {
3226
- const [schema, type] = getSchemaAndTableFromName(s);
3227
- return schema ? '"' + schema + '".' + type : type;
3228
- };
3229
- const quoteSchemaTable = (arg, excludeCurrentSchema) => {
3230
- return singleQuote(concatSchemaAndName(arg, excludeCurrentSchema));
3231
- };
3232
- const concatSchemaAndName = ({
3233
- schema,
3234
- name
3235
- }, excludeCurrentSchema) => {
3236
- return schema && schema !== excludeCurrentSchema ? `${schema}.${name}` : name;
3237
- };
3238
- const makePopulateEnumQuery = (item) => {
3239
- const [schema, name] = getSchemaAndTableFromName(item.enumName);
3240
- return {
3241
- text: `SELECT unnest(enum_range(NULL::${quoteTable(schema, name)}))::text`,
3242
- then(result) {
3243
- item.options.push(...result.rows.map(([value]) => value));
3244
- }
3245
- };
3246
- };
3247
- const transaction = (adapter, fn) => {
3248
- return adapter.transaction(void 0, fn);
3249
- };
3250
- const queryLock = (trx) => trx.query(`SELECT pg_advisory_xact_lock('${RAKE_DB_LOCK_KEY}')`);
3251
- const getCliParam = (args, name) => {
3252
- if (args) {
3253
- const key = "--" + name;
3254
- for (let i = 0; i < args.length; i += 1) {
3255
- const arg = args[i];
3256
- if (arg === key) return args[i + 1];
3257
- else if (arg.startsWith(key)) return arg.slice(key.length + 1);
3258
- }
3259
- }
3260
- return;
3261
- };
3262
-
3263
- const migrationConfigDefaults = {
3264
- schemaConfig: defaultSchemaConfig,
3265
- migrationsPath: path.join("src", "db", "migrations"),
3266
- migrationId: { serial: 4 },
3267
- migrationsTable: "schemaMigrations",
3268
- snakeCase: false,
3269
- commands: {},
3270
- log: true,
3271
- logger: console,
3272
- import() {
3273
- throw new Error(
3274
- "Add `import: (path) => import(path),` setting to `rakeDb` config"
3275
- );
3276
- }
3277
- };
3278
- const ensureMigrationsPath = (config) => {
3279
- if (!config.migrationsPath) {
3280
- config.migrationsPath = migrationConfigDefaults.migrationsPath;
3281
- }
3282
- if (!path.isAbsolute(config.migrationsPath)) {
3283
- config.migrationsPath = path.resolve(
3284
- config.basePath,
3285
- config.migrationsPath
3286
- );
3287
- }
3288
- return config;
3289
- };
3290
- const ensureBasePathAndDbScript = (config, intermediateCallers = 0) => {
3291
- if (config.basePath && config.dbScript) return config;
3292
- let filePath = getStackTrace()?.[3 + intermediateCallers]?.getFileName();
3293
- if (!filePath) {
3294
- throw new Error(
3295
- "Failed to determine path to db script. Please set basePath option of rakeDb"
3296
- );
3297
- }
3298
- if (filePath.startsWith("file://")) {
3299
- filePath = fileURLToPath(filePath);
3300
- }
3301
- const ext = path.extname(filePath);
3302
- if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
3303
- throw new Error(
3304
- `Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
3305
- );
3306
- }
3307
- config.basePath = path.dirname(filePath);
3308
- config.dbScript = path.basename(filePath);
3309
- return config;
3310
- };
3311
- const processRakeDbConfig = (config, args) => {
3312
- const result = { ...migrationConfigDefaults, ...config };
3313
- if (!result.log) {
3314
- delete result.logger;
3315
- }
3316
- ensureBasePathAndDbScript(result, 1);
3317
- ensureMigrationsPath(result);
3318
- if (!result.recurrentPath) {
3319
- result.recurrentPath = path.join(
3320
- result.migrationsPath,
3321
- "recurrent"
3322
- );
3323
- }
3324
- if ("recurrentPath" in result && !path.isAbsolute(result.recurrentPath)) {
3325
- result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
3326
- }
3327
- if ("baseTable" in config && config.baseTable) {
3328
- const { types, snakeCase, language } = config.baseTable.prototype;
3329
- result.columnTypes = types || makeColumnTypes(defaultSchemaConfig);
3330
- if (snakeCase) result.snakeCase = true;
3331
- if (language) result.language = language;
3332
- } else {
3333
- const ct = "columnTypes" in config && config.columnTypes;
3334
- result.columnTypes = (typeof ct === "function" ? ct(
3335
- makeColumnTypes(defaultSchemaConfig)
3336
- ) : ct) || makeColumnTypes(defaultSchemaConfig);
3337
- }
3338
- if (config.migrationId === "serial") {
3339
- result.migrationId = { serial: 4 };
3340
- }
3341
- const transaction = getCliParam(args, "transaction");
3342
- if (transaction) {
3343
- if (transaction !== "single" && transaction !== "per-migration") {
3344
- throw new Error(
3345
- `Unsupported transaction param ${transaction}, expected single or per-migration`
3346
- );
3347
- }
3348
- result.transaction = transaction;
3349
- } else if (!result.transaction) {
3350
- result.transaction = "single";
3351
- }
3352
- return result;
3353
- };
3354
-
3355
- const ESC = "\x1B";
3356
- const CSI = `${ESC}[`;
3357
- const cursorShow = `${CSI}?25h`;
3358
- const cursorHide = `${CSI}?25l`;
3359
- const { stdin, stdout } = process;
3360
- const visibleChars = (s) => s.replace(
3361
- // eslint-disable-next-line no-control-regex
3362
- /[\u001B\u009B][[\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\d\/#&.:=?%@~_]+)*|[a-zA-Z\d]+(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?\u0007)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PRZcf-ntqry=><~]))/g,
3363
- ""
3364
- ).length;
3365
- const clear = (text) => {
3366
- const rows = text.split(/\r?\n/).reduce(
3367
- (rows2, line) => rows2 + 1 + Math.floor(Math.max(visibleChars(line) - 1, 0) / stdout.columns),
3368
- 0
3369
- );
3370
- let clear2 = "";
3371
- for (let i = 0; i < rows; i++) {
3372
- clear2 += `${CSI}2K`;
3373
- if (i < rows - 1) {
3374
- clear2 += `${CSI}${i < rows - 1 ? "1A" : "G"}`;
3375
- }
3376
- }
3377
- return clear2;
3397
+ return clear2;
3378
3398
  };
3379
3399
  const prompt = async ({
3380
3400
  render,
@@ -3684,962 +3704,6 @@ const readdirRecursive = async (dirPath, cb) => {
3684
3704
  );
3685
3705
  };
3686
3706
 
3687
- const filterSchema = (table) => `${table} !~ '^pg_' AND ${table} != 'information_schema'`;
3688
- const jsonAgg = (sql2, as) => `(SELECT coalesce(json_agg(t.*), '[]') FROM (${sql2}) t) AS "${as}"`;
3689
- const columnsSql = ({
3690
- schema,
3691
- table,
3692
- join = "",
3693
- where
3694
- }) => `SELECT
3695
- ${schema}.nspname "schemaName",
3696
- ${table}.relname "tableName",
3697
- a.attname "name",
3698
- t.typname "type",
3699
- tn.nspname "typeSchema",
3700
- a.attndims "arrayDims",
3701
- information_schema._pg_char_max_length(tt.id, tt.mod) "maxChars",
3702
- information_schema._pg_numeric_precision(tt.id, tt.mod) "numericPrecision",
3703
- information_schema._pg_numeric_scale(tt.id,tt.mod) "numericScale",
3704
- information_schema._pg_datetime_precision(tt.id,tt.mod) "dateTimePrecision",
3705
- CAST(
3706
- CASE WHEN a.attgenerated = ''
3707
- THEN pg_get_expr(ad.adbin, ad.adrelid)
3708
- END AS information_schema.character_data
3709
- ) AS "default",
3710
- NOT (a.attnotnull OR (t.typtype = 'd' AND t.typnotnull)) AS "isNullable",
3711
- co.collname AS "collate",
3712
- NULLIF(a.attcompression, '') AS compression,
3713
- pgd.description AS "comment",
3714
- (
3715
- CASE WHEN a.attidentity IN ('a', 'd') THEN (
3716
- json_build_object(
3717
- 'always',
3718
- a.attidentity = 'a',
3719
- 'start',
3720
- seq.seqstart,
3721
- 'increment',
3722
- seq.seqincrement,
3723
- 'min',
3724
- nullif(seq.seqmin, 1),
3725
- 'max',
3726
- nullif(seq.seqmax, (
3727
- CASE t.typname
3728
- WHEN 'int2' THEN 32767
3729
- WHEN 'int4' THEN 2147483647
3730
- WHEN 'int8' THEN 9223372036854775807
3731
- ELSE NULL
3732
- END
3733
- )),
3734
- 'cache',
3735
- seq.seqcache,
3736
- 'cycle',
3737
- seq.seqcycle
3738
- )
3739
- ) END
3740
- ) "identity",
3741
- ext.extname "extension",
3742
- a.atttypmod "typmod"
3743
- FROM pg_attribute a
3744
- ${join}
3745
- LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
3746
- JOIN pg_type t
3747
- ON t.oid = (
3748
- CASE WHEN a.attndims = 0
3749
- THEN a.atttypid
3750
- ELSE (SELECT t.typelem FROM pg_type t WHERE t.oid = a.atttypid)
3751
- END
3752
- )
3753
- JOIN LATERAL (
3754
- SELECT
3755
- CASE WHEN t.typtype = 'd' THEN t.typbasetype ELSE t.oid END id,
3756
- CASE WHEN t.typtype = 'd' THEN t.typtypmod ELSE a.atttypmod END mod
3757
- ) tt ON true
3758
- JOIN pg_namespace tn ON tn.oid = t.typnamespace
3759
- LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid))
3760
- ON a.attcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default')
3761
- LEFT JOIN pg_catalog.pg_description pgd
3762
- ON pgd.objoid = a.attrelid
3763
- AND pgd.objsubid = a.attnum
3764
- LEFT JOIN (pg_depend dep JOIN pg_sequence seq ON (dep.classid = 'pg_class'::regclass AND dep.objid = seq.seqrelid AND dep.deptype = 'i'))
3765
- ON (dep.refclassid = 'pg_class'::regclass AND dep.refobjid = ${table}.oid AND dep.refobjsubid = a.attnum)
3766
- LEFT JOIN pg_depend d ON d.objid = t.oid AND d.classid = 'pg_type'::regclass AND d.deptype = 'e'
3767
- LEFT JOIN pg_extension ext ON ext.oid = d.refobjid
3768
- WHERE a.attnum > 0
3769
- AND NOT a.attisdropped
3770
- AND ${where}
3771
- ORDER BY a.attnum`;
3772
- const schemasSql = `SELECT coalesce(json_agg(nspname ORDER BY nspname), '[]')
3773
- FROM pg_catalog.pg_namespace n
3774
- WHERE ${filterSchema("nspname")}`;
3775
- const tablesSql = `SELECT
3776
- nspname AS "schemaName",
3777
- relname AS "name",
3778
- obj_description(c.oid) AS comment,
3779
- (SELECT coalesce(json_agg(t), '[]') FROM (${columnsSql({
3780
- schema: "n",
3781
- table: "c",
3782
- where: "a.attrelid = c.oid"
3783
- })}) t) AS "columns"
3784
- FROM pg_class c
3785
- JOIN pg_catalog.pg_namespace n ON n.oid = relnamespace
3786
- WHERE (relkind = 'r' OR relkind = 'p')
3787
- AND ${filterSchema("nspname")}
3788
- ORDER BY relname`;
3789
- const viewsSql = `SELECT
3790
- nc.nspname AS "schemaName",
3791
- c.relname AS "name",
3792
- (
3793
- SELECT COALESCE(json_agg(t.*), '[]')
3794
- FROM (
3795
- SELECT
3796
- ns.nspname AS "schemaName",
3797
- obj.relname AS "name"
3798
- FROM pg_class obj
3799
- JOIN pg_depend dep ON dep.refobjid = obj.oid
3800
- JOIN pg_rewrite rew ON rew.oid = dep.objid
3801
- JOIN pg_namespace ns ON ns.oid = obj.relnamespace
3802
- WHERE rew.ev_class = c.oid AND obj.oid <> c.oid
3803
- ) t
3804
- ) "deps",
3805
- right(substring(r.ev_action from ':hasRecursive w'), 1)::bool AS "isRecursive",
3806
- array_to_json(c.reloptions) AS "with",
3807
- (SELECT coalesce(json_agg(t), '[]') FROM (${columnsSql({
3808
- schema: "nc",
3809
- table: "c",
3810
- where: "a.attrelid = c.oid"
3811
- })}) t) AS "columns",
3812
- pg_get_viewdef(c.oid) AS "sql"
3813
- FROM pg_namespace nc
3814
- JOIN pg_class c
3815
- ON nc.oid = c.relnamespace
3816
- AND c.relkind = 'v'
3817
- AND c.relpersistence != 't'
3818
- JOIN pg_rewrite r ON r.ev_class = c.oid
3819
- WHERE ${filterSchema("nc.nspname")}
3820
- ORDER BY c.relname`;
3821
- const indexesSql = `SELECT
3822
- n.nspname "schemaName",
3823
- t.relname "tableName",
3824
- ic.relname "name",
3825
- am.amname AS "using",
3826
- i.indisunique "unique",
3827
- (
3828
- SELECT json_agg(
3829
- (
3830
- CASE WHEN t.e = 0
3831
- THEN jsonb_build_object('expression', pg_get_indexdef(i.indexrelid, t.i::int4, false))
3832
- ELSE jsonb_build_object('column', (
3833
- (
3834
- SELECT attname
3835
- FROM pg_catalog.pg_attribute
3836
- WHERE attrelid = i.indrelid
3837
- AND attnum = t.e
3838
- )
3839
- ))
3840
- END
3841
- ) || (
3842
- CASE WHEN i.indcollation[t.i - 1] = 0
3843
- THEN '{}'::jsonb
3844
- ELSE (
3845
- SELECT (
3846
- CASE WHEN collname = 'default'
3847
- THEN '{}'::jsonb
3848
- ELSE jsonb_build_object('collate', collname)
3849
- END
3850
- )
3851
- FROM pg_catalog.pg_collation
3852
- WHERE oid = i.indcollation[t.i - 1]
3853
- )
3854
- END
3855
- ) || (
3856
- SELECT
3857
- CASE WHEN opcdefault AND attoptions IS NULL
3858
- THEN '{}'::jsonb
3859
- ELSE jsonb_build_object(
3860
- 'opclass', opcname || COALESCE('(' || array_to_string(attoptions, ', ') || ')', '')
3861
- )
3862
- END
3863
- FROM pg_opclass
3864
- LEFT JOIN pg_attribute
3865
- ON attrelid = i.indexrelid
3866
- AND attnum = t.i
3867
- WHERE oid = i.indclass[t.i - 1]
3868
- ) || (
3869
- CASE WHEN i.indoption[t.i - 1] = 0
3870
- THEN '{}'::jsonb
3871
- ELSE jsonb_build_object(
3872
- 'order',
3873
- CASE
3874
- WHEN i.indoption[t.i - 1] = 1 THEN 'DESC NULLS LAST'
3875
- WHEN i.indoption[t.i - 1] = 2 THEN 'ASC NULLS FIRST'
3876
- WHEN i.indoption[t.i - 1] = 3 THEN 'DESC'
3877
- ELSE NULL
3878
- END
3879
- )
3880
- END
3881
- )
3882
- )
3883
- FROM unnest(i.indkey[:indnkeyatts - 1]) WITH ORDINALITY AS t(e, i)
3884
- ) "columns",
3885
- (
3886
- SELECT json_agg(
3887
- (
3888
- SELECT attname
3889
- FROM pg_catalog.pg_attribute
3890
- WHERE attrelid = i.indrelid
3891
- AND attnum = j.e
3892
- )
3893
- )
3894
- FROM unnest(i.indkey[indnkeyatts:]) AS j(e)
3895
- ) AS "include",
3896
- (to_jsonb(i.*)->'indnullsnotdistinct')::bool AS "nullsNotDistinct",
3897
- NULLIF(pg_catalog.array_to_string(
3898
- ic.reloptions || array(SELECT 'toast.' || x FROM pg_catalog.unnest(tc.reloptions) x),
3899
- ', '
3900
- ), '') AS "with",
3901
- (
3902
- SELECT tablespace
3903
- FROM pg_indexes
3904
- WHERE schemaname = n.nspname
3905
- AND indexname = ic.relname
3906
- ) AS tablespace,
3907
- pg_get_expr(i.indpred, i.indrelid) AS "where",
3908
- (
3909
- CASE i.indisexclusion WHEN true
3910
- THEN (
3911
- SELECT json_agg(o.oprname)
3912
- FROM pg_catalog.pg_constraint c, LATERAL unnest(c.conexclop) op_oid
3913
- JOIN pg_operator o ON o.oid = op_oid
3914
- WHERE c.conindid = ic.oid
3915
- )
3916
- END
3917
- ) "exclude"
3918
- FROM pg_index i
3919
- JOIN pg_class t ON t.oid = i.indrelid
3920
- JOIN pg_namespace n ON n.oid = t.relnamespace
3921
- JOIN pg_class ic ON ic.oid = i.indexrelid
3922
- JOIN pg_am am ON am.oid = ic.relam
3923
- LEFT JOIN pg_catalog.pg_class tc ON (ic.reltoastrelid = tc.oid)
3924
- WHERE ${filterSchema("n.nspname")}
3925
- AND NOT i.indisprimary
3926
- ORDER BY ic.relname`;
3927
- const constraintsSql = `SELECT
3928
- s.nspname AS "schemaName",
3929
- t.relname AS "tableName",
3930
- c.conname AS "name",
3931
- (
3932
- SELECT json_agg(ccu.column_name)
3933
- FROM information_schema.constraint_column_usage ccu
3934
- WHERE contype = 'p'
3935
- AND ccu.constraint_name = c.conname
3936
- AND ccu.table_schema = s.nspname
3937
- ) AS "primaryKey",
3938
- (
3939
- SELECT
3940
- json_build_object(
3941
- 'foreignSchema',
3942
- fs.nspname,
3943
- 'foreignTable',
3944
- ft.relname,
3945
- 'columns',
3946
- (
3947
- SELECT json_agg(ccu.column_name)
3948
- FROM information_schema.key_column_usage ccu
3949
- WHERE ccu.constraint_name = c.conname
3950
- AND ccu.table_schema = cs.nspname
3951
- ),
3952
- 'foreignColumns',
3953
- (
3954
- SELECT json_agg(ccu.column_name)
3955
- FROM information_schema.constraint_column_usage ccu
3956
- WHERE ccu.constraint_name = c.conname
3957
- AND ccu.table_schema = cs.nspname
3958
- ),
3959
- 'match',
3960
- c.confmatchtype,
3961
- 'onUpdate',
3962
- c.confupdtype,
3963
- 'onDelete',
3964
- c.confdeltype
3965
- )
3966
- FROM pg_class ft
3967
- JOIN pg_catalog.pg_namespace fs ON fs.oid = ft.relnamespace
3968
- JOIN pg_catalog.pg_namespace cs ON cs.oid = c.connamespace
3969
- WHERE contype = 'f' AND ft.oid = confrelid
3970
- ) AS "references",
3971
- (
3972
- SELECT
3973
- CASE conbin IS NULL
3974
- WHEN false THEN
3975
- json_build_object(
3976
- 'columns',
3977
- json_agg(ccu.column_name),
3978
- 'expression',
3979
- pg_get_expr(conbin, conrelid)
3980
- )
3981
- END
3982
- FROM information_schema.constraint_column_usage ccu
3983
- WHERE conbin IS NOT NULL
3984
- AND ccu.constraint_name = c.conname
3985
- AND ccu.table_schema = s.nspname
3986
- ) AS "check"
3987
- FROM pg_catalog.pg_constraint c
3988
- JOIN pg_class t ON t.oid = conrelid
3989
- JOIN pg_catalog.pg_namespace s
3990
- ON s.oid = t.relnamespace
3991
- AND contype IN ('p', 'f', 'c')
3992
- AND ${filterSchema("s.nspname")}
3993
- ORDER BY c.conname`;
3994
- const triggersSql = `SELECT event_object_schema AS "schemaName",
3995
- event_object_table AS "tableName",
3996
- trigger_schema AS "triggerSchema",
3997
- trigger_name AS name,
3998
- json_agg(event_manipulation) AS events,
3999
- action_timing AS activation,
4000
- action_condition AS condition,
4001
- action_statement AS definition
4002
- FROM information_schema.triggers
4003
- WHERE ${filterSchema("event_object_schema")}
4004
- GROUP BY event_object_schema, event_object_table, trigger_schema, trigger_name, action_timing, action_condition, action_statement
4005
- ORDER BY trigger_name`;
4006
- const extensionsSql = `SELECT
4007
- nspname AS "schemaName",
4008
- extname AS "name",
4009
- extversion AS version
4010
- FROM pg_extension
4011
- JOIN pg_catalog.pg_namespace n ON n.oid = extnamespace
4012
- AND ${filterSchema("n.nspname")}`;
4013
- const enumsSql = `SELECT
4014
- n.nspname as "schemaName",
4015
- t.typname as name,
4016
- json_agg(e.enumlabel ORDER BY e.enumsortorder) as values
4017
- FROM pg_type t
4018
- JOIN pg_enum e ON t.oid = e.enumtypid
4019
- JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
4020
- WHERE ${filterSchema("n.nspname")}
4021
- GROUP BY n.nspname, t.typname`;
4022
- const domainsSql = `SELECT
4023
- n.nspname AS "schemaName",
4024
- d.typname AS "name",
4025
- t.typname AS "type",
4026
- s.nspname AS "typeSchema",
4027
- NOT d.typnotnull AS "isNullable",
4028
- d.typndims AS "arrayDims",
4029
- character_maximum_length AS "maxChars",
4030
- numeric_precision AS "numericPrecision",
4031
- numeric_scale AS "numericScale",
4032
- datetime_precision AS "dateTimePrecision",
4033
- collation_name AS "collate",
4034
- domain_default AS "default",
4035
- (
4036
- SELECT json_agg(pg_get_expr(conbin, conrelid))
4037
- FROM pg_catalog.pg_constraint c
4038
- WHERE c.contypid = d.oid
4039
- ) AS "checks"
4040
- FROM pg_catalog.pg_type d
4041
- JOIN pg_catalog.pg_namespace n ON n.oid = d.typnamespace
4042
- JOIN information_schema.domains i
4043
- ON i.domain_schema = nspname
4044
- AND i.domain_name = d.typname
4045
- JOIN pg_catalog.pg_type t
4046
- ON (
4047
- CASE WHEN d.typcategory = 'A'
4048
- THEN t.typarray
4049
- ELSE t.oid
4050
- END
4051
- ) = d.typbasetype
4052
- JOIN pg_catalog.pg_namespace s ON s.oid = t.typnamespace
4053
- WHERE d.typtype = 'd' AND ${filterSchema("n.nspname")}`;
4054
- const collationsSql = (version) => `SELECT
4055
- nspname "schemaName",
4056
- collname "name",
4057
- CASE WHEN collprovider = 'i' THEN 'icu' WHEN collprovider = 'c' THEN 'libc' ELSE collprovider::text END "provider",
4058
- collisdeterministic "deterministic",
4059
- collcollate "lcCollate",
4060
- collctype "lcCType",
4061
- ${version >= 17 ? "colllocale" : "colliculocale"} "locale",
4062
- collversion "version"
4063
- FROM pg_collation
4064
- JOIN pg_namespace n on pg_collation.collnamespace = n.oid
4065
- WHERE ${filterSchema("n.nspname")}`;
4066
- const sql = (version) => `SELECT (${schemasSql}) AS "schemas", ${jsonAgg(
4067
- tablesSql,
4068
- "tables"
4069
- )}, ${jsonAgg(viewsSql, "views")}, ${jsonAgg(
4070
- indexesSql,
4071
- "indexes"
4072
- )}, ${jsonAgg(constraintsSql, "constraints")}, ${jsonAgg(
4073
- triggersSql,
4074
- "triggers"
4075
- )}, ${jsonAgg(extensionsSql, "extensions")}, ${jsonAgg(
4076
- enumsSql,
4077
- "enums"
4078
- )}, ${jsonAgg(domainsSql, "domains")}, ${jsonAgg(
4079
- collationsSql(version),
4080
- "collations"
4081
- )}`;
4082
- async function introspectDbSchema(db) {
4083
- const {
4084
- rows: [{ version: versionString }]
4085
- } = await db.query("SELECT version()");
4086
- const version = +versionString.match(/\d+/)[0];
4087
- const data = await db.query(sql(version));
4088
- const result = data.rows[0];
4089
- for (const domain of result.domains) {
4090
- domain.checks = domain.checks?.filter((check) => check);
4091
- nullsToUndefined(domain);
4092
- }
4093
- for (const table of result.tables) {
4094
- for (const column of table.columns) {
4095
- nullsToUndefined(column);
4096
- if (column.identity) nullsToUndefined(column.identity);
4097
- if (column.compression) {
4098
- column.compression = column.compression === "p" ? "pglz" : "lz4";
4099
- }
4100
- }
4101
- }
4102
- const indexes = [];
4103
- const excludes = [];
4104
- for (const index of result.indexes) {
4105
- nullsToUndefined(index);
4106
- for (const column of index.columns) {
4107
- if (!("expression" in column)) continue;
4108
- const s = column.expression;
4109
- const columnR = `"?\\w+"?`;
4110
- const langR = `(${columnR}|'\\w+'::regconfig)`;
4111
- const firstColumnR = `[(]*${columnR}`;
4112
- const concatR = `\\|\\|`;
4113
- const restColumnR = ` ${concatR} ' '::text\\) ${concatR} ${columnR}\\)`;
4114
- const coalesceColumn = `COALESCE\\(${columnR}, ''::text\\)`;
4115
- const tsVectorR = `to_tsvector\\(${langR}, (${firstColumnR}|${restColumnR}|${coalesceColumn})+\\)`;
4116
- const weightR = `'\\w'::"char"`;
4117
- const setWeightR = `setweight\\(${tsVectorR}, ${weightR}\\)`;
4118
- const setWeightOrTsVectorR = `(${setWeightR}|${tsVectorR})`;
4119
- const match = s.match(
4120
- new RegExp(`^([\\(]*${setWeightOrTsVectorR}[\\)]*( ${concatR} )?)+$`)
4121
- );
4122
- if (!match) continue;
4123
- let language;
4124
- let languageColumn;
4125
- const tokens = match[0].match(
4126
- new RegExp(
4127
- `setweight\\(|to_tsvector\\(${langR}|[:']?${columnR}\\(?`,
4128
- "g"
4129
- )
4130
- )?.reduce((acc, token) => {
4131
- if (token === "setweight(" || token === "COALESCE(" || token[0] === ":")
4132
- return acc;
4133
- if (token.startsWith("to_tsvector(")) {
4134
- if (token[12] === "'") {
4135
- language = token.slice(13, -12);
4136
- } else {
4137
- languageColumn = token.slice(12);
4138
- }
4139
- } else if (token[0] === "'") {
4140
- acc.push({ kind: "weight", value: token[1] });
4141
- } else {
4142
- if (token[0] === '"') token = token.slice(1, -1);
4143
- acc.push({ kind: "column", value: token });
4144
- }
4145
- return acc;
4146
- }, []);
4147
- if (!tokens) continue;
4148
- index.language = language;
4149
- index.languageColumn = languageColumn;
4150
- index.tsVector = true;
4151
- index.columns = [];
4152
- for (const token of tokens) {
4153
- if (token.kind === "column") {
4154
- index.columns.push({
4155
- column: token.value
4156
- });
4157
- } else if (token.kind === "weight") {
4158
- index.columns[index.columns.length - 1].weight = token.value;
4159
- }
4160
- }
4161
- }
4162
- (index.exclude ? excludes : indexes).push(index);
4163
- }
4164
- result.indexes = indexes;
4165
- result.excludes = excludes;
4166
- return result;
4167
- }
4168
- const nullsToUndefined = (obj) => {
4169
- for (const key in obj) {
4170
- if (obj[key] === null)
4171
- obj[key] = void 0;
4172
- }
4173
- };
4174
-
4175
- const matchMap = {
4176
- s: void 0,
4177
- f: "FULL",
4178
- p: "PARTIAL"
4179
- };
4180
- const fkeyActionMap = {
4181
- a: void 0,
4182
- // default
4183
- r: "RESTRICT",
4184
- c: "CASCADE",
4185
- n: "SET NULL",
4186
- d: "SET DEFAULT"
4187
- };
4188
- const makeStructureToAstCtx = (config, currentSchema) => ({
4189
- snakeCase: config.snakeCase,
4190
- unsupportedTypes: {},
4191
- currentSchema,
4192
- columnSchemaConfig: config.schemaConfig,
4193
- columnsByType: makeColumnsByType(config.schemaConfig)
4194
- });
4195
- const structureToAst = async (ctx, adapter, config) => {
4196
- const ast = [];
4197
- const data = await introspectDbSchema(adapter);
4198
- for (const name of data.schemas) {
4199
- if (name === "public") continue;
4200
- ast.push({
4201
- type: "schema",
4202
- action: "create",
4203
- name
4204
- });
4205
- }
4206
- for (const it of data.collations) {
4207
- ast.push({
4208
- type: "collation",
4209
- action: "create",
4210
- ...it,
4211
- schema: it.schemaName === ctx.currentSchema ? void 0 : it.schemaName
4212
- });
4213
- }
4214
- const domains = makeDomainsMap(ctx, data);
4215
- for (const table of data.tables) {
4216
- if (table.name === config.migrationsTable) continue;
4217
- ast.push(tableToAst(ctx, data, table, "create", domains));
4218
- }
4219
- for (const it of data.extensions) {
4220
- ast.push({
4221
- type: "extension",
4222
- action: "create",
4223
- name: it.name,
4224
- schema: it.schemaName === ctx.currentSchema ? void 0 : it.schemaName,
4225
- version: it.version
4226
- });
4227
- }
4228
- for (const it of data.enums) {
4229
- ast.push({
4230
- type: "enum",
4231
- action: "create",
4232
- name: it.name,
4233
- schema: it.schemaName === ctx.currentSchema ? void 0 : it.schemaName,
4234
- values: it.values
4235
- });
4236
- }
4237
- for (const it of data.domains) {
4238
- ast.push({
4239
- type: "domain",
4240
- action: "create",
4241
- schema: it.schemaName === ctx.currentSchema ? void 0 : it.schemaName,
4242
- name: it.name,
4243
- baseType: domains[`${it.schemaName}.${it.name}`]
4244
- });
4245
- }
4246
- for (const table of data.tables) {
4247
- for (const fkey of data.constraints) {
4248
- if (fkey.references && fkey.tableName === table.name && fkey.schemaName === table.schemaName && checkIfIsOuterRecursiveFkey(data, table, fkey.references)) {
4249
- ast.push({
4250
- ...constraintToAst(ctx, fkey),
4251
- type: "constraint",
4252
- action: "create",
4253
- tableSchema: table.schemaName === ctx.currentSchema ? void 0 : table.schemaName,
4254
- tableName: fkey.tableName
4255
- });
4256
- }
4257
- }
4258
- }
4259
- for (const view of data.views) {
4260
- ast.push(viewToAst(ctx, data, domains, view));
4261
- }
4262
- return ast;
4263
- };
4264
- const makeDomainsMap = (ctx, data) => {
4265
- const domains = {};
4266
- for (const it of data.domains) {
4267
- const column = instantiateDbColumn(ctx, data, domains, {
4268
- schemaName: it.schemaName,
4269
- name: it.name,
4270
- type: it.type,
4271
- typeSchema: it.typeSchema,
4272
- arrayDims: it.arrayDims,
4273
- tableName: "",
4274
- isNullable: it.isNullable,
4275
- collate: it.collate,
4276
- default: it.default,
4277
- typmod: -1
4278
- });
4279
- if (it.checks) {
4280
- column.data.checks = it.checks.map((check) => ({
4281
- sql: new RawSql([[check]])
4282
- }));
4283
- }
4284
- domains[`${it.schemaName}.${it.name}`] = column;
4285
- }
4286
- return domains;
4287
- };
4288
- const getDbColumnIsSerial = (item) => {
4289
- if (item.type === "int2" || item.type === "int4" || item.type === "int8") {
4290
- const { default: def, schemaName, tableName, name } = item;
4291
- const seq = `${tableName}_${name}_seq`;
4292
- if (def && (def === `nextval(${singleQuote(`${seq}`)}::regclass)` || def === `nextval(${singleQuote(`"${seq}"`)}::regclass)` || def === `nextval(${singleQuote(`${schemaName}.${seq}`)}::regclass)` || def === `nextval(${singleQuote(`"${schemaName}".${seq}`)}::regclass)` || def === `nextval(${singleQuote(`${schemaName}."${seq}"`)}::regclass)` || def === `nextval(${singleQuote(`"${schemaName}"."${seq}"`)}::regclass)`)) {
4293
- return true;
4294
- }
4295
- }
4296
- return false;
4297
- };
4298
- const instantiateDbColumn = (ctx, data, domains, dbColumn) => {
4299
- var _a, _b;
4300
- const isSerial = getDbColumnIsSerial(dbColumn);
4301
- if (isSerial) {
4302
- dbColumn = { ...dbColumn, default: void 0 };
4303
- }
4304
- let column;
4305
- const col = instantiateColumnByDbType(ctx, dbColumn.type, isSerial, dbColumn);
4306
- if (col) {
4307
- column = col;
4308
- } else {
4309
- const { typeSchema, type: typeName } = dbColumn;
4310
- const typeId = typeSchema === "pg_catalog" ? typeName : `${typeSchema}.${typeName}`;
4311
- const domainColumn = domains[typeId];
4312
- if (domainColumn) {
4313
- column = new DomainColumn(
4314
- ctx.columnSchemaConfig,
4315
- typeName,
4316
- typeSchema,
4317
- dbColumn.extension
4318
- ).as(domainColumn);
4319
- } else {
4320
- const enumType = data.enums.find(
4321
- (x) => x.name === typeName && x.schemaName === typeSchema
4322
- );
4323
- if (enumType) {
4324
- column = new EnumColumn(
4325
- ctx.columnSchemaConfig,
4326
- typeSchema === ctx.currentSchema ? typeName : typeId,
4327
- enumType.values,
4328
- ctx.columnSchemaConfig.type
4329
- );
4330
- } else {
4331
- column = new CustomTypeColumn(
4332
- ctx.columnSchemaConfig,
4333
- typeName,
4334
- typeSchema === "pg_catalog" ? void 0 : typeSchema,
4335
- dbColumn.extension
4336
- );
4337
- ((_a = ctx.unsupportedTypes)[_b = dbColumn.type] ?? (_a[_b] = [])).push(
4338
- `${dbColumn.schemaName}${dbColumn.tableName ? `.${dbColumn.tableName}` : ""}.${dbColumn.name}`
4339
- );
4340
- }
4341
- assignDbDataToColumn(column, dbColumn);
4342
- }
4343
- }
4344
- column.data.name = void 0;
4345
- if (!column.data.isNullable) column.data.isNullable = void 0;
4346
- if (dbColumn.arrayDims) {
4347
- const arr = new ArrayColumn(
4348
- ctx.columnSchemaConfig,
4349
- column,
4350
- ctx.columnSchemaConfig.type
4351
- );
4352
- arr.data.isNullable = dbColumn.isNullable;
4353
- arr.data.arrayDims = dbColumn.arrayDims;
4354
- column = arr;
4355
- }
4356
- return column;
4357
- };
4358
- const instantiateColumnByDbType = (ctx, type, isSerial, params) => {
4359
- let columnFn = ctx.columnsByType[!isSerial ? type : type === "int2" ? "smallserial" : type === "int4" ? "serial" : "bigserial"];
4360
- if (!columnFn && params.extension === "postgis" && type === "geography" && PostgisGeographyPointColumn.isDefaultPoint(params.typmod)) {
4361
- columnFn = ctx.columnsByType.geographyDefaultPoint;
4362
- }
4363
- return columnFn ? assignDbDataToColumn(columnFn(), params) : void 0;
4364
- };
4365
- const tableToAst = (ctx, data, table, action, domains) => {
4366
- const { schemaName, name: tableName } = table;
4367
- const tableData = getDbStructureTableData(data, table);
4368
- const { primaryKey, constraints } = tableData;
4369
- return {
4370
- type: "table",
4371
- action,
4372
- schema: schemaName === ctx.currentSchema ? void 0 : schemaName,
4373
- comment: table.comment,
4374
- name: tableName,
4375
- shape: makeDbStructureColumnsShape(ctx, data, domains, table, tableData),
4376
- noPrimaryKey: tableData.primaryKey ? "error" : "ignore",
4377
- primaryKey: primaryKey && primaryKey.columns.length > 1 ? { ...primaryKey, columns: primaryKey.columns.map(toCamelCase) } : void 0,
4378
- indexes: indexesOrExcludesToAst(
4379
- tableName,
4380
- tableData,
4381
- "indexes"
4382
- ),
4383
- excludes: indexesOrExcludesToAst(
4384
- tableName,
4385
- tableData,
4386
- "excludes"
4387
- ),
4388
- constraints: constraints.reduce((acc, it) => {
4389
- if (it.check && it.references || it.check && it.check.columns?.length !== 1 || it.references && it.references.columns.length !== 1 && !checkIfIsOuterRecursiveFkey(data, table, it.references)) {
4390
- acc.push(dbConstraintToTableConstraint(ctx, table, it));
4391
- }
4392
- return acc;
4393
- }, [])
4394
- };
4395
- };
4396
- const indexesOrExcludesToAst = (tableName, tableData, key) => {
4397
- return tableData[key].reduce((acc, item) => {
4398
- if (item.columns.length > 1 || item.columns.some((it) => "expression" in it)) {
4399
- const options = makeIndexOrExcludeOptions(tableName, item, key);
4400
- acc.push({
4401
- columns: item.columns.map((it, i) => ({
4402
- with: "exclude" in item && item.exclude ? item.exclude[i] : void 0,
4403
- ..."expression" in it ? { expression: it.expression } : { column: toCamelCase(it.column) },
4404
- collate: it.collate,
4405
- opclass: it.opclass,
4406
- order: it.order
4407
- })),
4408
- options: {
4409
- ...options,
4410
- include: item.include?.map(toCamelCase)
4411
- }
4412
- });
4413
- }
4414
- return acc;
4415
- }, []);
4416
- };
4417
- const getDbStructureTableData = (data, { name, schemaName }) => {
4418
- const filterFn = filterByTableSchema(name, schemaName);
4419
- const constraints = data.constraints.filter(filterFn);
4420
- const primaryKey = constraints.find((c) => c.primaryKey);
4421
- return {
4422
- primaryKey: primaryKey?.primaryKey ? {
4423
- columns: primaryKey.primaryKey,
4424
- name: primaryKey.name === `${name}_pkey` ? void 0 : primaryKey.name
4425
- } : void 0,
4426
- indexes: data.indexes.filter(filterFn),
4427
- excludes: data.excludes.filter(filterFn),
4428
- constraints
4429
- };
4430
- };
4431
- const filterByTableSchema = (tableName, schemaName) => (x) => x.tableName === tableName && x.schemaName === schemaName;
4432
- const constraintToAst = (ctx, item) => {
4433
- const result = {};
4434
- const { references, check } = item;
4435
- if (references) {
4436
- const options = {};
4437
- result.references = {
4438
- columns: references.columns,
4439
- fnOrTable: getReferencesTable(ctx, references),
4440
- foreignColumns: references.foreignColumns,
4441
- options
4442
- };
4443
- const match = matchMap[references.match];
4444
- if (match) options.match = match;
4445
- const onUpdate = fkeyActionMap[references.onUpdate];
4446
- if (onUpdate) options.onUpdate = onUpdate;
4447
- const onDelete = fkeyActionMap[references.onDelete];
4448
- if (onDelete) options.onDelete = onDelete;
4449
- }
4450
- if (check) {
4451
- result.check = raw({ raw: check.expression });
4452
- }
4453
- if (item.name && item.name !== getConstraintName(item.tableName, result, ctx.snakeCase)) {
4454
- result.name = item.name;
4455
- if (result.references?.options) {
4456
- result.references.options.name = item.name;
4457
- }
4458
- }
4459
- return result;
4460
- };
4461
- const getReferencesTable = (ctx, references) => {
4462
- return references.foreignSchema !== ctx.currentSchema ? `${references.foreignSchema}.${references.foreignTable}` : references.foreignTable;
4463
- };
4464
- const isColumnCheck = (it) => {
4465
- return !it.references && it.check?.columns?.length === 1;
4466
- };
4467
- const viewToAst = (ctx, data, domains, view) => {
4468
- const shape = makeDbStructureColumnsShape(ctx, data, domains, view);
4469
- const options = {};
4470
- if (view.isRecursive) options.recursive = true;
4471
- if (view.with) {
4472
- const withOptions = {};
4473
- options.with = withOptions;
4474
- for (const pair of view.with) {
4475
- const [key, value] = pair.split("=");
4476
- withOptions[toCamelCase(key)] = value === "true" ? true : value === "false" ? false : value;
4477
- }
4478
- }
4479
- return {
4480
- type: "view",
4481
- action: "create",
4482
- schema: view.schemaName === ctx.currentSchema ? void 0 : view.schemaName,
4483
- name: view.name,
4484
- shape,
4485
- sql: raw({ raw: view.sql }),
4486
- options,
4487
- deps: view.deps
4488
- };
4489
- };
4490
- const makeDbStructureColumnsShape = (ctx, data, domains, table, tableData) => {
4491
- const shape = {};
4492
- const checks = tableData ? getDbTableColumnsChecks(tableData) : void 0;
4493
- for (const item of table.columns) {
4494
- const [key, column] = dbColumnToAst(
4495
- ctx,
4496
- data,
4497
- domains,
4498
- table.name,
4499
- item,
4500
- table,
4501
- tableData,
4502
- checks
4503
- );
4504
- shape[key] = column;
4505
- }
4506
- return shape;
4507
- };
4508
- const getDbTableColumnsChecks = (tableData) => tableData.constraints.reduce((acc, item) => {
4509
- var _a;
4510
- if (isColumnCheck(item)) {
4511
- (acc[_a = item.check.columns[0]] ?? (acc[_a] = [])).push(item.check.expression);
4512
- }
4513
- return acc;
4514
- }, {});
4515
- const dbColumnToAst = (ctx, data, domains, tableName, item, table, tableData, checks) => {
4516
- let column = instantiateDbColumn(ctx, data, domains, item);
4517
- column.data.name = item.name;
4518
- if (item.identity) {
4519
- column.data.identity = item.identity;
4520
- if (!item.identity.always) delete column.data.identity?.always;
4521
- }
4522
- if (tableData?.primaryKey?.columns?.length === 1 && tableData?.primaryKey?.columns[0] === item.name) {
4523
- column = column.primaryKey();
4524
- }
4525
- collectColumnIndexesOrExcludes(item, column, tableName, tableData, "indexes");
4526
- collectColumnIndexesOrExcludes(
4527
- item,
4528
- column,
4529
- tableName,
4530
- tableData,
4531
- "excludes"
4532
- );
4533
- if (table) {
4534
- for (const it of data.constraints) {
4535
- if (it.tableName !== table.name || it.schemaName !== table.schemaName || it.check || it.references?.columns.length !== 1 || it.references.columns[0] !== item.name || checkIfIsOuterRecursiveFkey(data, table, it.references)) {
4536
- continue;
4537
- }
4538
- const c = dbConstraintToTableConstraint(ctx, table, it);
4539
- column = column.foreignKey(
4540
- c.references?.fnOrTable,
4541
- it.references.foreignColumns[0],
4542
- c.references?.options
4543
- );
4544
- }
4545
- }
4546
- const columnChecks = checks?.[item.name];
4547
- if (columnChecks) {
4548
- column.data.checks = columnChecks.map((check) => ({
4549
- sql: new RawSql([[check]])
4550
- }));
4551
- }
4552
- const camelCaseName = toCamelCase(item.name);
4553
- if (ctx.snakeCase) {
4554
- const snakeCaseName = toSnakeCase(camelCaseName);
4555
- if (snakeCaseName !== item.name) column.data.name = item.name;
4556
- } else if (camelCaseName !== item.name) {
4557
- column.data.name = item.name;
4558
- }
4559
- return [camelCaseName, column];
4560
- };
4561
- const collectColumnIndexesOrExcludes = (dbColumn, column, tableName, tableData, key) => {
4562
- var _a;
4563
- const items = tableData?.[key];
4564
- if (!items) return;
4565
- const columnItems = items.filter(
4566
- (it) => it.columns.length === 1 && "column" in it.columns[0] && it.columns[0].column === dbColumn.name
4567
- );
4568
- for (const item of columnItems) {
4569
- const columnOptions = item.columns[0];
4570
- const { name, ...itemOptions } = makeIndexOrExcludeOptions(
4571
- tableName,
4572
- item,
4573
- key
4574
- );
4575
- ((_a = column.data)[key] ?? (_a[key] = [])).push({
4576
- with: "exclude" in item && item.exclude ? item.exclude[0] : void 0,
4577
- options: {
4578
- name,
4579
- collate: columnOptions.collate,
4580
- opclass: columnOptions.opclass,
4581
- order: columnOptions.order,
4582
- ...itemOptions
4583
- }
4584
- });
4585
- }
4586
- };
4587
- const dbConstraintToTableConstraint = (ctx, table, item) => {
4588
- const { references, check } = item;
4589
- const constraint = {
4590
- references: references ? {
4591
- columns: references.columns,
4592
- fnOrTable: getReferencesTable(ctx, references),
4593
- foreignColumns: references.foreignColumns,
4594
- options: {
4595
- match: matchMap[references.match],
4596
- onUpdate: fkeyActionMap[references.onUpdate],
4597
- onDelete: fkeyActionMap[references.onDelete]
4598
- }
4599
- } : void 0,
4600
- check: check ? raw({ raw: check.expression }) : void 0
4601
- };
4602
- const name = item.name && item.name !== getConstraintName(table.name, constraint, ctx.snakeCase) ? item.name : void 0;
4603
- if (name) {
4604
- constraint.name = name;
4605
- if (constraint.references?.options) {
4606
- constraint.references.options.name = name;
4607
- }
4608
- }
4609
- return constraint;
4610
- };
4611
- const makeIndexOrExcludeOptions = (tableName, index, key) => {
4612
- return {
4613
- name: index.name !== (key === "indexes" ? getIndexName : getExcludeName)(
4614
- tableName,
4615
- index.columns
4616
- ) ? index.name : void 0,
4617
- using: index.using === "btree" ? void 0 : index.using,
4618
- unique: index.unique || void 0,
4619
- include: index.include,
4620
- nullsNotDistinct: index.nullsNotDistinct || void 0,
4621
- with: index.with,
4622
- tablespace: index.tablespace,
4623
- where: index.where
4624
- };
4625
- };
4626
- const checkIfIsOuterRecursiveFkey = (data, table, references) => {
4627
- const referencesId = `${references.foreignSchema}.${references.foreignTable}`;
4628
- const tableId = `${table.schemaName}.${table.name}`;
4629
- for (const other of data.tables) {
4630
- const id = `${other.schemaName}.${other.name}`;
4631
- if (referencesId === id) {
4632
- for (const c of data.constraints) {
4633
- if (c.tableName === other.name && c.schemaName === other.schemaName && c.references?.foreignTable === table.name && c.references.foreignSchema === table.schemaName && tableId < id) {
4634
- return true;
4635
- }
4636
- }
4637
- break;
4638
- }
4639
- }
4640
- return false;
4641
- };
4642
-
4643
3707
  const astToGenerateItems = (config, asts, currentSchema) => {
4644
3708
  return asts.map((ast) => astToGenerateItem(config, ast, currentSchema));
4645
3709
  };
@@ -5025,23 +4089,79 @@ const astEncoders = {
5025
4089
  const inner = [`${quoteSchemaTable(ast)},`];
5026
4090
  code.push(inner);
5027
4091
  code = inner;
5028
- if (hasOptions) {
5029
- const options = [];
5030
- if (ast.comment)
5031
- options.push(`comment: ${JSON.stringify(ast.comment)},`);
5032
- if (ast.noPrimaryKey === "ignore") options.push(`noPrimaryKey: true,`);
5033
- code.push("{", options, "},");
5034
- }
5035
- code.push("(t) => ({");
4092
+ if (hasOptions) {
4093
+ const options = [];
4094
+ if (ast.comment)
4095
+ options.push(`comment: ${JSON.stringify(ast.comment)},`);
4096
+ if (ast.noPrimaryKey === "ignore") options.push(`noPrimaryKey: true,`);
4097
+ code.push("{", options, "},");
4098
+ }
4099
+ code.push("(t) => ({");
4100
+ } else {
4101
+ addCode(
4102
+ code,
4103
+ `await db.${ast.action}Table(${quoteSchemaTable(ast)}, (t) => ({`
4104
+ );
4105
+ }
4106
+ const timestamps = getHasTimestamps(
4107
+ ast.shape.createdAt,
4108
+ ast.shape.updatedAt
4109
+ );
4110
+ const toCodeCtx = {
4111
+ t: "t",
4112
+ table: ast.name,
4113
+ currentSchema,
4114
+ migration: true,
4115
+ snakeCase: config.snakeCase
4116
+ };
4117
+ for (const key in ast.shape) {
4118
+ if (timestamps.hasAnyTimestamps && (key === "createdAt" || key === "updatedAt"))
4119
+ continue;
4120
+ const line = [`${quoteObjectKey(key, config.snakeCase)}: `];
4121
+ const columnCode = ast.shape[key].toCode(toCodeCtx, key);
4122
+ for (const part of columnCode) {
4123
+ addCode(line, part);
4124
+ }
4125
+ addCode(line, ",");
4126
+ code.push(line);
4127
+ }
4128
+ if (timestamps.hasAnyTimestamps) {
4129
+ code.push([`...${timestampsToCode(timestamps)},`]);
4130
+ }
4131
+ if (isShifted) {
4132
+ addCode(code, "}),");
4133
+ if (hasTableData) pushTableDataCode(code, ast);
4134
+ addCode(result, ");");
4135
+ } else {
4136
+ addCode(result, "}));");
4137
+ }
4138
+ return result;
4139
+ },
4140
+ changeTable(ast, config, currentSchema) {
4141
+ let code = [];
4142
+ const result = code;
4143
+ const schemaTable = quoteSchemaTable({
4144
+ schema: ast.schema === currentSchema ? void 0 : ast.schema,
4145
+ name: ast.name
4146
+ });
4147
+ const { comment } = ast;
4148
+ if (comment !== void 0) {
4149
+ addCode(code, `await db.changeTable(`);
4150
+ const inner = [
4151
+ `${schemaTable},`,
4152
+ `{ comment: ${JSON.stringify(ast.comment)} },`,
4153
+ "(t) => ({"
4154
+ ];
4155
+ code.push(inner);
4156
+ code = inner;
5036
4157
  } else {
5037
- addCode(
5038
- code,
5039
- `await db.${ast.action}Table(${quoteSchemaTable(ast)}, (t) => ({`
5040
- );
4158
+ addCode(code, `await db.changeTable(${schemaTable}, (t) => ({`);
5041
4159
  }
5042
- const timestamps = getHasTimestamps(
5043
- ast.shape.createdAt,
5044
- ast.shape.updatedAt
4160
+ const [addTimestamps, dropTimestamps] = ["add", "drop"].map(
4161
+ (type) => getHasTimestamps(
4162
+ ast.shape.createdAt && "type" in ast.shape.createdAt && ast.shape.createdAt?.type === type ? ast.shape.createdAt.item : void 0,
4163
+ ast.shape.updatedAt && "type" in ast.shape.updatedAt && ast.shape.updatedAt?.type === type ? ast.shape.updatedAt.item : void 0
4164
+ )
5045
4165
  );
5046
4166
  const toCodeCtx = {
5047
4167
  t: "t",
@@ -5051,349 +4171,1251 @@ const astEncoders = {
5051
4171
  snakeCase: config.snakeCase
5052
4172
  };
5053
4173
  for (const key in ast.shape) {
5054
- if (timestamps.hasAnyTimestamps && (key === "createdAt" || key === "updatedAt"))
5055
- continue;
5056
- const line = [`${quoteObjectKey(key, config.snakeCase)}: `];
5057
- const columnCode = ast.shape[key].toCode(toCodeCtx, key);
5058
- for (const part of columnCode) {
5059
- addCode(line, part);
4174
+ const changes = toArray(ast.shape[key]);
4175
+ for (const change of changes) {
4176
+ if (change.type === "add" || change.type === "drop") {
4177
+ if ((addTimestamps.hasAnyTimestamps || dropTimestamps.hasAnyTimestamps) && (key === "createdAt" || key === "updatedAt"))
4178
+ continue;
4179
+ const recreate = changes.length > 1;
4180
+ const line = [
4181
+ recreate ? `...t.${change.type}(t.name(${singleQuote(
4182
+ change.item.data.name ?? key
4183
+ )})` : `${quoteObjectKey(key, config.snakeCase)}: t.${change.type}(`
4184
+ ];
4185
+ const columnCode = change.item.toCode(toCodeCtx, key);
4186
+ for (let i = 0; i < columnCode.length; i++) {
4187
+ let part = columnCode[i];
4188
+ if (recreate && !i) part = part.slice(1);
4189
+ addCode(line, part);
4190
+ }
4191
+ addCode(line, "),");
4192
+ code.push(line);
4193
+ } else if (change.type === "change") {
4194
+ if (!change.from.column || !change.to.column) continue;
4195
+ const line = [
4196
+ `${quoteObjectKey(key, config.snakeCase)}: t${change.name ? `.name(${singleQuote(change.name)})` : ""}.change(`
4197
+ ];
4198
+ const fromCode = change.from.column.toCode(
4199
+ {
4200
+ t: "t",
4201
+ table: ast.name,
4202
+ currentSchema,
4203
+ migration: true,
4204
+ snakeCase: config.snakeCase
4205
+ },
4206
+ key
4207
+ );
4208
+ for (const part of fromCode) {
4209
+ addCode(line, part);
4210
+ }
4211
+ addCode(line, ", ");
4212
+ const toCode = change.to.column.toCode(toCodeCtx, key);
4213
+ for (const part of toCode) {
4214
+ addCode(line, part);
4215
+ }
4216
+ if (change.using) {
4217
+ addCode(line, ", {");
4218
+ const u = [];
4219
+ if (change.using.usingUp) {
4220
+ u.push(`usingUp: ${rawSqlToCode(change.using.usingUp, "t")},`);
4221
+ }
4222
+ if (change.using.usingDown) {
4223
+ u.push(
4224
+ `usingDown: ${rawSqlToCode(change.using.usingDown, "t")},`
4225
+ );
4226
+ }
4227
+ addCode(line, u);
4228
+ addCode(line, "}");
4229
+ }
4230
+ addCode(line, "),");
4231
+ code.push(line);
4232
+ } else if (change.type === "rename") {
4233
+ code.push([
4234
+ `${quoteObjectKey(key, config.snakeCase)}: t.rename(${singleQuote(
4235
+ change.name
4236
+ )}),`
4237
+ ]);
4238
+ } else {
4239
+ exhaustive(change.type);
4240
+ }
5060
4241
  }
5061
- addCode(line, ",");
5062
- code.push(line);
5063
4242
  }
5064
- if (timestamps.hasAnyTimestamps) {
5065
- code.push([`...${timestampsToCode(timestamps)},`]);
4243
+ for (const key of ["drop", "add"]) {
4244
+ const timestamps = key === "add" ? addTimestamps : dropTimestamps;
4245
+ if (timestamps.hasAnyTimestamps) {
4246
+ addCode(code, [`...t.${key}(${timestampsToCode(timestamps)}),`]);
4247
+ }
4248
+ const { primaryKey, indexes, excludes, constraints } = ast[key];
4249
+ if (primaryKey) {
4250
+ addCode(code, [
4251
+ `...t.${key}(${primaryKeyInnerToCode(primaryKey, "t")}),`
4252
+ ]);
4253
+ }
4254
+ if (indexes) {
4255
+ for (const item of indexes) {
4256
+ addCode(code, [`...t.${key}(`, indexInnerToCode(item, "t"), "),"]);
4257
+ }
4258
+ }
4259
+ if (excludes) {
4260
+ for (const item of excludes) {
4261
+ addCode(code, [`...t.${key}(`, excludeInnerToCode(item, "t"), "),"]);
4262
+ }
4263
+ }
4264
+ if (constraints) {
4265
+ for (const item of constraints) {
4266
+ addCode(code, [
4267
+ `...t.${key}(`,
4268
+ constraintInnerToCode(item, "t", true),
4269
+ "),"
4270
+ ]);
4271
+ }
4272
+ }
5066
4273
  }
5067
- if (isShifted) {
4274
+ if (ast.comment !== void 0) {
5068
4275
  addCode(code, "}),");
5069
- if (hasTableData) pushTableDataCode(code, ast);
5070
4276
  addCode(result, ");");
5071
4277
  } else {
5072
4278
  addCode(result, "}));");
5073
4279
  }
5074
- return result;
5075
- },
5076
- changeTable(ast, config, currentSchema) {
5077
- let code = [];
5078
- const result = code;
5079
- const schemaTable = quoteSchemaTable({
5080
- schema: ast.schema === currentSchema ? void 0 : ast.schema,
5081
- name: ast.name
5082
- });
5083
- const { comment } = ast;
5084
- if (comment !== void 0) {
5085
- addCode(code, `await db.changeTable(`);
5086
- const inner = [
5087
- `${schemaTable},`,
5088
- `{ comment: ${JSON.stringify(ast.comment)} },`,
5089
- "(t) => ({"
5090
- ];
5091
- code.push(inner);
5092
- code = inner;
4280
+ return result;
4281
+ },
4282
+ renameType(ast, _, currentSchema) {
4283
+ const code = [];
4284
+ const kind = ast.kind === "TABLE" ? "Table" : "Type";
4285
+ if (ast.from === ast.to) {
4286
+ addCode(
4287
+ code,
4288
+ `await db.change${kind}Schema(${singleQuote(ast.to)}, ${singleQuote(
4289
+ ast.fromSchema ?? currentSchema
4290
+ )}, ${singleQuote(ast.toSchema ?? currentSchema)});`
4291
+ );
4292
+ } else {
4293
+ addCode(
4294
+ code,
4295
+ `await db.rename${kind}(${quoteSchemaTable({
4296
+ schema: ast.fromSchema === currentSchema ? void 0 : ast.fromSchema,
4297
+ name: ast.from
4298
+ })}, ${quoteSchemaTable({
4299
+ schema: ast.toSchema === currentSchema ? void 0 : ast.toSchema,
4300
+ name: ast.to
4301
+ })});`
4302
+ );
4303
+ }
4304
+ return code;
4305
+ },
4306
+ schema(ast) {
4307
+ return `await db.${ast.action === "create" ? "createSchema" : "dropSchema"}(${singleQuote(ast.name)});`;
4308
+ },
4309
+ renameSchema(ast) {
4310
+ return `await db.renameSchema(${singleQuote(ast.from)}, ${singleQuote(
4311
+ ast.to
4312
+ )});`;
4313
+ },
4314
+ extension(ast) {
4315
+ const code = [
4316
+ `await db.${ast.action}Extension(${quoteSchemaTable(ast)}`
4317
+ ];
4318
+ if (ast.version) {
4319
+ addCode(code, ", {");
4320
+ code.push([`version: ${singleQuote(ast.version)},`], "}");
4321
+ }
4322
+ addCode(code, ");");
4323
+ return code;
4324
+ },
4325
+ enum(ast, _, currentSchema) {
4326
+ return `await db.${ast.action === "create" ? "createEnum" : "dropEnum"}(${quoteSchemaTable(ast, currentSchema)}, [${ast.values.map(singleQuote).join(", ")}]);`;
4327
+ },
4328
+ enumValues(ast, _, currentSchema) {
4329
+ return `await db.${ast.action}EnumValues(${quoteSchemaTable(
4330
+ ast,
4331
+ currentSchema
4332
+ )}, [${ast.values.map(singleQuote).join(", ")}]);`;
4333
+ },
4334
+ renameEnumValues(ast, config, currentSchema) {
4335
+ return `await db.renameEnumValues(${quoteSchemaTable(
4336
+ ast,
4337
+ currentSchema
4338
+ )}, { ${Object.entries(ast.values).map(
4339
+ ([from, to]) => `${quoteObjectKey(from, config.snakeCase)}: ${singleQuote(to)}`
4340
+ ).join(", ")} });`;
4341
+ },
4342
+ changeEnumValues(ast, _, currentSchema) {
4343
+ return `await db.changeEnumValues(${quoteSchemaTable(
4344
+ ast,
4345
+ currentSchema
4346
+ )}, [${ast.fromValues.map(singleQuote).join(", ")}], [${ast.toValues.map(singleQuote).join(", ")}]);`;
4347
+ },
4348
+ domain(ast, _, currentSchema) {
4349
+ return `await db.${ast.action}Domain(${quoteSchemaTable(
4350
+ ast
4351
+ )}, (t) => ${ast.baseType.toCode(
4352
+ { t: "t", table: ast.name, currentSchema },
4353
+ ast.baseType.data.name ?? ""
4354
+ )});`;
4355
+ },
4356
+ collation(ast) {
4357
+ const params = [];
4358
+ if (ast.locale) params.push(`locale: '${ast.locale}',`);
4359
+ if (ast.lcCollate) params.push(`lcCollate: '${ast.lcCollate}',`);
4360
+ if (ast.lcCType) params.push(`lcCType: '${ast.lcCType}',`);
4361
+ if (ast.provider) params.push(`provider: '${ast.provider}',`);
4362
+ if (ast.deterministic) params.push(`deterministic: ${ast.deterministic},`);
4363
+ if (ast.version) params.push(`version: '${ast.version}',`);
4364
+ return [
4365
+ `await db.createCollation(${quoteSchemaTable(ast)}, {`,
4366
+ params,
4367
+ "});"
4368
+ ];
4369
+ },
4370
+ constraint(ast) {
4371
+ const table = quoteSchemaTable({
4372
+ schema: ast.tableSchema,
4373
+ name: ast.tableName
4374
+ });
4375
+ if (ast.references) {
4376
+ return [
4377
+ `await db.addForeignKey(`,
4378
+ [`${table},`, ...referencesArgsToCode(ast.references, ast.name, true)],
4379
+ ");"
4380
+ ];
4381
+ }
4382
+ const check = ast.check;
4383
+ return [
4384
+ `await db.addCheck(${table}, ${rawSqlToCode(check, "t")}${ast.name ? `, ${singleQuote(ast.name)}` : ""});`
4385
+ ];
4386
+ },
4387
+ renameTableItem(ast) {
4388
+ return [
4389
+ `await db.rename${ast.kind === "INDEX" ? "Index" : "Constraint"}(${quoteSchemaTable({
4390
+ schema: ast.tableSchema,
4391
+ name: ast.tableName
4392
+ })}, ${singleQuote(ast.from)}, ${singleQuote(ast.to)});`
4393
+ ];
4394
+ },
4395
+ view(ast) {
4396
+ const code = [`await db.createView(${quoteSchemaTable(ast)}`];
4397
+ const options = [];
4398
+ if (ast.options.recursive) options.push("recursive: true,");
4399
+ const w = ast.options.with;
4400
+ if (w?.checkOption) options.push(`checkOption: '${w.checkOption}',`);
4401
+ if (w?.securityBarrier)
4402
+ options.push(`securityBarrier: ${w.securityBarrier},`);
4403
+ if (w?.securityInvoker)
4404
+ options.push(`securityInvoker: ${w.securityInvoker},`);
4405
+ if (options.length) {
4406
+ addCode(code, ", {");
4407
+ code.push(options, "}");
4408
+ }
4409
+ addCode(code, ", ");
4410
+ if (!ast.sql._values) {
4411
+ const raw = ast.sql._sql;
4412
+ let sql;
4413
+ if (typeof raw === "string") {
4414
+ sql = raw;
4415
+ } else {
4416
+ sql = "";
4417
+ const parts = raw[0];
4418
+ const last = parts.length - 1;
4419
+ for (let i = 0; i < last; i++) {
4420
+ sql += parts[i] + `\${${raw[i + 1]}}`;
4421
+ }
4422
+ sql += parts[last];
4423
+ }
4424
+ addCode(code, backtickQuote(sql));
5093
4425
  } else {
5094
- addCode(code, `await db.changeTable(${schemaTable}, (t) => ({`);
4426
+ addCode(code, rawSqlToCode(ast.sql, "db"));
5095
4427
  }
5096
- const [addTimestamps, dropTimestamps] = ["add", "drop"].map(
5097
- (type) => getHasTimestamps(
5098
- ast.shape.createdAt && "type" in ast.shape.createdAt && ast.shape.createdAt?.type === type ? ast.shape.createdAt.item : void 0,
5099
- ast.shape.updatedAt && "type" in ast.shape.updatedAt && ast.shape.updatedAt?.type === type ? ast.shape.updatedAt.item : void 0
4428
+ addCode(code, ");");
4429
+ return code;
4430
+ }
4431
+ };
4432
+ const isTimestamp = (column, type) => {
4433
+ if (!column) return false;
4434
+ const { default: def } = column.data;
4435
+ return Boolean(
4436
+ column instanceof type && !column.data.isNullable && def && typeof def === "object" && isRawSQL(def) && (typeof def._sql === "object" ? def._sql[0][0] : def._sql) === "now()"
4437
+ );
4438
+ };
4439
+ const getHasTimestamps = (createdAt, updatedAt) => {
4440
+ const timestamps = getTimestampsInfo(createdAt, updatedAt, TimestampTZColumn);
4441
+ const timestampsNoTZ = getTimestampsInfo(
4442
+ createdAt,
4443
+ updatedAt,
4444
+ TimestampColumn
4445
+ );
4446
+ return {
4447
+ hasTZTimestamps: timestamps,
4448
+ hasAnyTimestamps: timestamps || timestampsNoTZ
4449
+ };
4450
+ };
4451
+ const getTimestampsInfo = (createdAt, updatedAt, type) => {
4452
+ return isTimestamp(createdAt, type) && isTimestamp(updatedAt, type) && (!createdAt?.data.name || createdAt?.data.name === "created_at") && (!updatedAt?.data.name || updatedAt?.data.name === "updated_at");
4453
+ };
4454
+ const timestampsToCode = ({ hasTZTimestamps }) => {
4455
+ const key = hasTZTimestamps ? "timestamps" : "timestampsNoTZ";
4456
+ return `t.${key}()`;
4457
+ };
4458
+
4459
+ const filterSchema = (table) => `${table} !~ '^pg_' AND ${table} != 'information_schema'`;
4460
+ const jsonAgg = (sql2, as) => `(SELECT coalesce(json_agg(t.*), '[]') FROM (${sql2}) t) AS "${as}"`;
4461
+ const columnsSql = ({
4462
+ schema,
4463
+ table,
4464
+ join = "",
4465
+ where
4466
+ }) => `SELECT
4467
+ ${schema}.nspname "schemaName",
4468
+ ${table}.relname "tableName",
4469
+ a.attname "name",
4470
+ t.typname "type",
4471
+ tn.nspname "typeSchema",
4472
+ a.attndims "arrayDims",
4473
+ information_schema._pg_char_max_length(tt.id, tt.mod) "maxChars",
4474
+ information_schema._pg_numeric_precision(tt.id, tt.mod) "numericPrecision",
4475
+ information_schema._pg_numeric_scale(tt.id,tt.mod) "numericScale",
4476
+ information_schema._pg_datetime_precision(tt.id,tt.mod) "dateTimePrecision",
4477
+ CAST(
4478
+ CASE WHEN a.attgenerated = ''
4479
+ THEN pg_get_expr(ad.adbin, ad.adrelid)
4480
+ END AS information_schema.character_data
4481
+ ) AS "default",
4482
+ NOT (a.attnotnull OR (t.typtype = 'd' AND t.typnotnull)) AS "isNullable",
4483
+ co.collname AS "collate",
4484
+ NULLIF(a.attcompression, '') AS compression,
4485
+ pgd.description AS "comment",
4486
+ (
4487
+ CASE WHEN a.attidentity IN ('a', 'd') THEN (
4488
+ json_build_object(
4489
+ 'always',
4490
+ a.attidentity = 'a',
4491
+ 'start',
4492
+ seq.seqstart,
4493
+ 'increment',
4494
+ seq.seqincrement,
4495
+ 'min',
4496
+ nullif(seq.seqmin, 1),
4497
+ 'max',
4498
+ nullif(seq.seqmax, (
4499
+ CASE t.typname
4500
+ WHEN 'int2' THEN 32767
4501
+ WHEN 'int4' THEN 2147483647
4502
+ WHEN 'int8' THEN 9223372036854775807
4503
+ ELSE NULL
4504
+ END
4505
+ )),
4506
+ 'cache',
4507
+ seq.seqcache,
4508
+ 'cycle',
4509
+ seq.seqcycle
4510
+ )
4511
+ ) END
4512
+ ) "identity",
4513
+ ext.extname "extension",
4514
+ a.atttypmod "typmod"
4515
+ FROM pg_attribute a
4516
+ ${join}
4517
+ LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
4518
+ JOIN pg_type t
4519
+ ON t.oid = (
4520
+ CASE WHEN a.attndims = 0
4521
+ THEN a.atttypid
4522
+ ELSE (SELECT t.typelem FROM pg_type t WHERE t.oid = a.atttypid)
4523
+ END
4524
+ )
4525
+ JOIN LATERAL (
4526
+ SELECT
4527
+ CASE WHEN t.typtype = 'd' THEN t.typbasetype ELSE t.oid END id,
4528
+ CASE WHEN t.typtype = 'd' THEN t.typtypmod ELSE a.atttypmod END mod
4529
+ ) tt ON true
4530
+ JOIN pg_namespace tn ON tn.oid = t.typnamespace
4531
+ LEFT JOIN (pg_collation co JOIN pg_namespace nco ON (co.collnamespace = nco.oid))
4532
+ ON a.attcollation = co.oid AND (nco.nspname, co.collname) <> ('pg_catalog', 'default')
4533
+ LEFT JOIN pg_catalog.pg_description pgd
4534
+ ON pgd.objoid = a.attrelid
4535
+ AND pgd.objsubid = a.attnum
4536
+ LEFT JOIN (pg_depend dep JOIN pg_sequence seq ON (dep.classid = 'pg_class'::regclass AND dep.objid = seq.seqrelid AND dep.deptype = 'i'))
4537
+ ON (dep.refclassid = 'pg_class'::regclass AND dep.refobjid = ${table}.oid AND dep.refobjsubid = a.attnum)
4538
+ LEFT JOIN pg_depend d ON d.objid = t.oid AND d.classid = 'pg_type'::regclass AND d.deptype = 'e'
4539
+ LEFT JOIN pg_extension ext ON ext.oid = d.refobjid
4540
+ WHERE a.attnum > 0
4541
+ AND NOT a.attisdropped
4542
+ AND ${where}
4543
+ ORDER BY a.attnum`;
4544
+ const schemasSql = `SELECT coalesce(json_agg(nspname ORDER BY nspname), '[]')
4545
+ FROM pg_catalog.pg_namespace n
4546
+ WHERE ${filterSchema("nspname")}`;
4547
+ const tablesSql = `SELECT
4548
+ nspname AS "schemaName",
4549
+ relname AS "name",
4550
+ obj_description(c.oid) AS comment,
4551
+ (SELECT coalesce(json_agg(t), '[]') FROM (${columnsSql({
4552
+ schema: "n",
4553
+ table: "c",
4554
+ where: "a.attrelid = c.oid"
4555
+ })}) t) AS "columns"
4556
+ FROM pg_class c
4557
+ JOIN pg_catalog.pg_namespace n ON n.oid = relnamespace
4558
+ WHERE (relkind = 'r' OR relkind = 'p')
4559
+ AND ${filterSchema("nspname")}
4560
+ ORDER BY relname`;
4561
+ const viewsSql = `SELECT
4562
+ nc.nspname AS "schemaName",
4563
+ c.relname AS "name",
4564
+ (
4565
+ SELECT COALESCE(json_agg(t.*), '[]')
4566
+ FROM (
4567
+ SELECT
4568
+ ns.nspname AS "schemaName",
4569
+ obj.relname AS "name"
4570
+ FROM pg_class obj
4571
+ JOIN pg_depend dep ON dep.refobjid = obj.oid
4572
+ JOIN pg_rewrite rew ON rew.oid = dep.objid
4573
+ JOIN pg_namespace ns ON ns.oid = obj.relnamespace
4574
+ WHERE rew.ev_class = c.oid AND obj.oid <> c.oid
4575
+ ) t
4576
+ ) "deps",
4577
+ right(substring(r.ev_action from ':hasRecursive \\w'), 1)::bool AS "isRecursive",
4578
+ array_to_json(c.reloptions) AS "with",
4579
+ (SELECT coalesce(json_agg(t), '[]') FROM (${columnsSql({
4580
+ schema: "nc",
4581
+ table: "c",
4582
+ where: "a.attrelid = c.oid"
4583
+ })}) t) AS "columns",
4584
+ pg_get_viewdef(c.oid) AS "sql"
4585
+ FROM pg_namespace nc
4586
+ JOIN pg_class c
4587
+ ON nc.oid = c.relnamespace
4588
+ AND c.relkind = 'v'
4589
+ AND c.relpersistence != 't'
4590
+ JOIN pg_rewrite r ON r.ev_class = c.oid
4591
+ WHERE ${filterSchema("nc.nspname")}
4592
+ ORDER BY c.relname`;
4593
+ const indexesSql = `SELECT
4594
+ n.nspname "schemaName",
4595
+ t.relname "tableName",
4596
+ ic.relname "name",
4597
+ am.amname AS "using",
4598
+ i.indisunique "unique",
4599
+ (
4600
+ SELECT json_agg(
4601
+ (
4602
+ CASE WHEN t.e = 0
4603
+ THEN jsonb_build_object('expression', pg_get_indexdef(i.indexrelid, t.i::int4, false))
4604
+ ELSE jsonb_build_object('column', (
4605
+ (
4606
+ SELECT attname
4607
+ FROM pg_catalog.pg_attribute
4608
+ WHERE attrelid = i.indrelid
4609
+ AND attnum = t.e
4610
+ )
4611
+ ))
4612
+ END
4613
+ ) || (
4614
+ CASE WHEN i.indcollation[t.i - 1] = 0
4615
+ THEN '{}'::jsonb
4616
+ ELSE (
4617
+ SELECT (
4618
+ CASE WHEN collname = 'default'
4619
+ THEN '{}'::jsonb
4620
+ ELSE jsonb_build_object('collate', collname)
4621
+ END
4622
+ )
4623
+ FROM pg_catalog.pg_collation
4624
+ WHERE oid = i.indcollation[t.i - 1]
4625
+ )
4626
+ END
4627
+ ) || (
4628
+ SELECT
4629
+ CASE WHEN opcdefault AND attoptions IS NULL
4630
+ THEN '{}'::jsonb
4631
+ ELSE jsonb_build_object(
4632
+ 'opclass', opcname || COALESCE('(' || array_to_string(attoptions, ', ') || ')', '')
4633
+ )
4634
+ END
4635
+ FROM pg_opclass
4636
+ LEFT JOIN pg_attribute
4637
+ ON attrelid = i.indexrelid
4638
+ AND attnum = t.i
4639
+ WHERE oid = i.indclass[t.i - 1]
4640
+ ) || (
4641
+ CASE WHEN i.indoption[t.i - 1] = 0
4642
+ THEN '{}'::jsonb
4643
+ ELSE jsonb_build_object(
4644
+ 'order',
4645
+ CASE
4646
+ WHEN i.indoption[t.i - 1] = 1 THEN 'DESC NULLS LAST'
4647
+ WHEN i.indoption[t.i - 1] = 2 THEN 'ASC NULLS FIRST'
4648
+ WHEN i.indoption[t.i - 1] = 3 THEN 'DESC'
4649
+ ELSE NULL
4650
+ END
4651
+ )
4652
+ END
5100
4653
  )
5101
- );
5102
- const toCodeCtx = {
5103
- t: "t",
5104
- table: ast.name,
5105
- currentSchema,
5106
- migration: true,
5107
- snakeCase: config.snakeCase
5108
- };
5109
- for (const key in ast.shape) {
5110
- const changes = toArray(ast.shape[key]);
5111
- for (const change of changes) {
5112
- if (change.type === "add" || change.type === "drop") {
5113
- if ((addTimestamps.hasAnyTimestamps || dropTimestamps.hasAnyTimestamps) && (key === "createdAt" || key === "updatedAt"))
5114
- continue;
5115
- const recreate = changes.length > 1;
5116
- const line = [
5117
- recreate ? `...t.${change.type}(t.name(${singleQuote(
5118
- change.item.data.name ?? key
5119
- )})` : `${quoteObjectKey(key, config.snakeCase)}: t.${change.type}(`
5120
- ];
5121
- const columnCode = change.item.toCode(toCodeCtx, key);
5122
- for (let i = 0; i < columnCode.length; i++) {
5123
- let part = columnCode[i];
5124
- if (recreate && !i) part = part.slice(1);
5125
- addCode(line, part);
5126
- }
5127
- addCode(line, "),");
5128
- code.push(line);
5129
- } else if (change.type === "change") {
5130
- if (!change.from.column || !change.to.column) continue;
5131
- const line = [
5132
- `${quoteObjectKey(key, config.snakeCase)}: t${change.name ? `.name(${singleQuote(change.name)})` : ""}.change(`
5133
- ];
5134
- const fromCode = change.from.column.toCode(
5135
- {
5136
- t: "t",
5137
- table: ast.name,
5138
- currentSchema,
5139
- migration: true,
5140
- snakeCase: config.snakeCase
5141
- },
5142
- key
5143
- );
5144
- for (const part of fromCode) {
5145
- addCode(line, part);
5146
- }
5147
- addCode(line, ", ");
5148
- const toCode = change.to.column.toCode(toCodeCtx, key);
5149
- for (const part of toCode) {
5150
- addCode(line, part);
5151
- }
5152
- if (change.using) {
5153
- addCode(line, ", {");
5154
- const u = [];
5155
- if (change.using.usingUp) {
5156
- u.push(`usingUp: ${rawSqlToCode(change.using.usingUp, "t")},`);
5157
- }
5158
- if (change.using.usingDown) {
5159
- u.push(
5160
- `usingDown: ${rawSqlToCode(change.using.usingDown, "t")},`
5161
- );
5162
- }
5163
- addCode(line, u);
5164
- addCode(line, "}");
5165
- }
5166
- addCode(line, "),");
5167
- code.push(line);
5168
- } else if (change.type === "rename") {
5169
- code.push([
5170
- `${quoteObjectKey(key, config.snakeCase)}: t.rename(${singleQuote(
5171
- change.name
5172
- )}),`
5173
- ]);
5174
- } else {
5175
- exhaustive(change.type);
5176
- }
4654
+ )
4655
+ FROM unnest(i.indkey[:indnkeyatts - 1]) WITH ORDINALITY AS t(e, i)
4656
+ ) "columns",
4657
+ (
4658
+ SELECT json_agg(
4659
+ (
4660
+ SELECT attname
4661
+ FROM pg_catalog.pg_attribute
4662
+ WHERE attrelid = i.indrelid
4663
+ AND attnum = j.e
4664
+ )
4665
+ )
4666
+ FROM unnest(i.indkey[indnkeyatts:]) AS j(e)
4667
+ ) AS "include",
4668
+ (to_jsonb(i.*)->'indnullsnotdistinct')::bool AS "nullsNotDistinct",
4669
+ NULLIF(pg_catalog.array_to_string(
4670
+ ic.reloptions || array(SELECT 'toast.' || x FROM pg_catalog.unnest(tc.reloptions) x),
4671
+ ', '
4672
+ ), '') AS "with",
4673
+ (
4674
+ SELECT tablespace
4675
+ FROM pg_indexes
4676
+ WHERE schemaname = n.nspname
4677
+ AND indexname = ic.relname
4678
+ ) AS tablespace,
4679
+ pg_get_expr(i.indpred, i.indrelid) AS "where",
4680
+ (
4681
+ CASE i.indisexclusion WHEN true
4682
+ THEN (
4683
+ SELECT json_agg(o.oprname)
4684
+ FROM pg_catalog.pg_constraint c, LATERAL unnest(c.conexclop) op_oid
4685
+ JOIN pg_operator o ON o.oid = op_oid
4686
+ WHERE c.conindid = ic.oid
4687
+ )
4688
+ END
4689
+ ) "exclude"
4690
+ FROM pg_index i
4691
+ JOIN pg_class t ON t.oid = i.indrelid
4692
+ JOIN pg_namespace n ON n.oid = t.relnamespace
4693
+ JOIN pg_class ic ON ic.oid = i.indexrelid
4694
+ JOIN pg_am am ON am.oid = ic.relam
4695
+ LEFT JOIN pg_catalog.pg_class tc ON (ic.reltoastrelid = tc.oid)
4696
+ WHERE ${filterSchema("n.nspname")}
4697
+ AND NOT i.indisprimary
4698
+ ORDER BY ic.relname`;
4699
+ const constraintsSql = `SELECT
4700
+ s.nspname AS "schemaName",
4701
+ t.relname AS "tableName",
4702
+ c.conname AS "name",
4703
+ (
4704
+ SELECT json_agg(ccu.column_name)
4705
+ FROM information_schema.constraint_column_usage ccu
4706
+ WHERE contype = 'p'
4707
+ AND ccu.constraint_name = c.conname
4708
+ AND ccu.table_schema = s.nspname
4709
+ ) AS "primaryKey",
4710
+ (
4711
+ SELECT
4712
+ json_build_object(
4713
+ 'foreignSchema',
4714
+ fs.nspname,
4715
+ 'foreignTable',
4716
+ ft.relname,
4717
+ 'columns',
4718
+ (
4719
+ SELECT json_agg(ccu.column_name)
4720
+ FROM information_schema.key_column_usage ccu
4721
+ WHERE ccu.constraint_name = c.conname
4722
+ AND ccu.table_schema = cs.nspname
4723
+ ),
4724
+ 'foreignColumns',
4725
+ (
4726
+ SELECT json_agg(ccu.column_name)
4727
+ FROM information_schema.constraint_column_usage ccu
4728
+ WHERE ccu.constraint_name = c.conname
4729
+ AND ccu.table_schema = cs.nspname
4730
+ ),
4731
+ 'match',
4732
+ c.confmatchtype,
4733
+ 'onUpdate',
4734
+ c.confupdtype,
4735
+ 'onDelete',
4736
+ c.confdeltype
4737
+ )
4738
+ FROM pg_class ft
4739
+ JOIN pg_catalog.pg_namespace fs ON fs.oid = ft.relnamespace
4740
+ JOIN pg_catalog.pg_namespace cs ON cs.oid = c.connamespace
4741
+ WHERE contype = 'f' AND ft.oid = confrelid
4742
+ ) AS "references",
4743
+ (
4744
+ SELECT
4745
+ CASE conbin IS NULL
4746
+ WHEN false THEN
4747
+ json_build_object(
4748
+ 'columns',
4749
+ json_agg(ccu.column_name),
4750
+ 'expression',
4751
+ pg_get_expr(conbin, conrelid)
4752
+ )
4753
+ END
4754
+ FROM information_schema.constraint_column_usage ccu
4755
+ WHERE conbin IS NOT NULL
4756
+ AND ccu.constraint_name = c.conname
4757
+ AND ccu.table_schema = s.nspname
4758
+ ) AS "check"
4759
+ FROM pg_catalog.pg_constraint c
4760
+ JOIN pg_class t ON t.oid = conrelid
4761
+ JOIN pg_catalog.pg_namespace s
4762
+ ON s.oid = t.relnamespace
4763
+ AND contype IN ('p', 'f', 'c')
4764
+ AND ${filterSchema("s.nspname")}
4765
+ ORDER BY c.conname`;
4766
+ const triggersSql = `SELECT event_object_schema AS "schemaName",
4767
+ event_object_table AS "tableName",
4768
+ trigger_schema AS "triggerSchema",
4769
+ trigger_name AS name,
4770
+ json_agg(event_manipulation) AS events,
4771
+ action_timing AS activation,
4772
+ action_condition AS condition,
4773
+ action_statement AS definition
4774
+ FROM information_schema.triggers
4775
+ WHERE ${filterSchema("event_object_schema")}
4776
+ GROUP BY event_object_schema, event_object_table, trigger_schema, trigger_name, action_timing, action_condition, action_statement
4777
+ ORDER BY trigger_name`;
4778
+ const extensionsSql = `SELECT
4779
+ nspname AS "schemaName",
4780
+ extname AS "name",
4781
+ extversion AS version
4782
+ FROM pg_extension
4783
+ JOIN pg_catalog.pg_namespace n ON n.oid = extnamespace
4784
+ AND ${filterSchema("n.nspname")}`;
4785
+ const enumsSql = `SELECT
4786
+ n.nspname as "schemaName",
4787
+ t.typname as name,
4788
+ json_agg(e.enumlabel ORDER BY e.enumsortorder) as values
4789
+ FROM pg_type t
4790
+ JOIN pg_enum e ON t.oid = e.enumtypid
4791
+ JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
4792
+ WHERE ${filterSchema("n.nspname")}
4793
+ GROUP BY n.nspname, t.typname`;
4794
+ const domainsSql = `SELECT
4795
+ n.nspname AS "schemaName",
4796
+ d.typname AS "name",
4797
+ t.typname AS "type",
4798
+ s.nspname AS "typeSchema",
4799
+ NOT d.typnotnull AS "isNullable",
4800
+ d.typndims AS "arrayDims",
4801
+ character_maximum_length AS "maxChars",
4802
+ numeric_precision AS "numericPrecision",
4803
+ numeric_scale AS "numericScale",
4804
+ datetime_precision AS "dateTimePrecision",
4805
+ collation_name AS "collate",
4806
+ domain_default AS "default",
4807
+ (
4808
+ SELECT json_agg(pg_get_expr(conbin, conrelid))
4809
+ FROM pg_catalog.pg_constraint c
4810
+ WHERE c.contypid = d.oid
4811
+ ) AS "checks"
4812
+ FROM pg_catalog.pg_type d
4813
+ JOIN pg_catalog.pg_namespace n ON n.oid = d.typnamespace
4814
+ JOIN information_schema.domains i
4815
+ ON i.domain_schema = nspname
4816
+ AND i.domain_name = d.typname
4817
+ JOIN pg_catalog.pg_type t
4818
+ ON (
4819
+ CASE WHEN d.typcategory = 'A'
4820
+ THEN t.typarray
4821
+ ELSE t.oid
4822
+ END
4823
+ ) = d.typbasetype
4824
+ JOIN pg_catalog.pg_namespace s ON s.oid = t.typnamespace
4825
+ WHERE d.typtype = 'd' AND ${filterSchema("n.nspname")}`;
4826
+ const collationsSql = (version) => `SELECT
4827
+ nspname "schemaName",
4828
+ collname "name",
4829
+ CASE WHEN collprovider = 'i' THEN 'icu' WHEN collprovider = 'c' THEN 'libc' ELSE collprovider::text END "provider",
4830
+ collisdeterministic "deterministic",
4831
+ collcollate "lcCollate",
4832
+ collctype "lcCType",
4833
+ ${version >= 17 ? "colllocale" : "colliculocale"} "locale",
4834
+ collversion "version"
4835
+ FROM pg_collation
4836
+ JOIN pg_namespace n on pg_collation.collnamespace = n.oid
4837
+ WHERE ${filterSchema("n.nspname")}`;
4838
+ const sql = (version) => `SELECT (${schemasSql}) AS "schemas", ${jsonAgg(
4839
+ tablesSql,
4840
+ "tables"
4841
+ )}, ${jsonAgg(viewsSql, "views")}, ${jsonAgg(
4842
+ indexesSql,
4843
+ "indexes"
4844
+ )}, ${jsonAgg(constraintsSql, "constraints")}, ${jsonAgg(
4845
+ triggersSql,
4846
+ "triggers"
4847
+ )}, ${jsonAgg(extensionsSql, "extensions")}, ${jsonAgg(
4848
+ enumsSql,
4849
+ "enums"
4850
+ )}, ${jsonAgg(domainsSql, "domains")}, ${jsonAgg(
4851
+ collationsSql(version),
4852
+ "collations"
4853
+ )}`;
4854
+ async function introspectDbSchema(db) {
4855
+ const {
4856
+ rows: [{ version: versionString }]
4857
+ } = await db.query("SELECT version()");
4858
+ const version = +versionString.match(/\d+/)[0];
4859
+ const data = await db.query(sql(version));
4860
+ const result = data.rows[0];
4861
+ for (const domain of result.domains) {
4862
+ domain.checks = domain.checks?.filter((check) => check);
4863
+ nullsToUndefined(domain);
4864
+ }
4865
+ for (const table of result.tables) {
4866
+ for (const column of table.columns) {
4867
+ nullsToUndefined(column);
4868
+ if (column.identity) nullsToUndefined(column.identity);
4869
+ if (column.compression) {
4870
+ column.compression = column.compression === "p" ? "pglz" : "lz4";
5177
4871
  }
5178
4872
  }
5179
- for (const key of ["drop", "add"]) {
5180
- const timestamps = key === "add" ? addTimestamps : dropTimestamps;
5181
- if (timestamps.hasAnyTimestamps) {
5182
- addCode(code, [`...t.${key}(${timestampsToCode(timestamps)}),`]);
5183
- }
5184
- const { primaryKey, indexes, excludes, constraints } = ast[key];
5185
- if (primaryKey) {
5186
- addCode(code, [
5187
- `...t.${key}(${primaryKeyInnerToCode(primaryKey, "t")}),`
5188
- ]);
5189
- }
5190
- if (indexes) {
5191
- for (const item of indexes) {
5192
- addCode(code, [`...t.${key}(`, indexInnerToCode(item, "t"), "),"]);
4873
+ }
4874
+ const indexes = [];
4875
+ const excludes = [];
4876
+ for (const index of result.indexes) {
4877
+ nullsToUndefined(index);
4878
+ for (const column of index.columns) {
4879
+ if (!("expression" in column)) continue;
4880
+ const s = column.expression;
4881
+ const columnR = `"?\\w+"?`;
4882
+ const langR = `(${columnR}|'\\w+'::regconfig)`;
4883
+ const firstColumnR = `[(]*${columnR}`;
4884
+ const concatR = `\\|\\|`;
4885
+ const restColumnR = ` ${concatR} ' '::text\\) ${concatR} ${columnR}\\)`;
4886
+ const coalesceColumn = `COALESCE\\(${columnR}, ''::text\\)`;
4887
+ const tsVectorR = `to_tsvector\\(${langR}, (${firstColumnR}|${restColumnR}|${coalesceColumn})+\\)`;
4888
+ const weightR = `'\\w'::"char"`;
4889
+ const setWeightR = `setweight\\(${tsVectorR}, ${weightR}\\)`;
4890
+ const setWeightOrTsVectorR = `(${setWeightR}|${tsVectorR})`;
4891
+ const match = s.match(
4892
+ new RegExp(`^([\\(]*${setWeightOrTsVectorR}[\\)]*( ${concatR} )?)+$`)
4893
+ );
4894
+ if (!match) continue;
4895
+ let language;
4896
+ let languageColumn;
4897
+ const tokens = match[0].match(
4898
+ new RegExp(
4899
+ `setweight\\(|to_tsvector\\(${langR}|[:']?${columnR}\\(?`,
4900
+ "g"
4901
+ )
4902
+ )?.reduce((acc, token) => {
4903
+ if (token === "setweight(" || token === "COALESCE(" || token[0] === ":")
4904
+ return acc;
4905
+ if (token.startsWith("to_tsvector(")) {
4906
+ if (token[12] === "'") {
4907
+ language = token.slice(13, -12);
4908
+ } else {
4909
+ languageColumn = token.slice(12);
4910
+ }
4911
+ } else if (token[0] === "'") {
4912
+ acc.push({ kind: "weight", value: token[1] });
4913
+ } else {
4914
+ if (token[0] === '"') token = token.slice(1, -1);
4915
+ acc.push({ kind: "column", value: token });
5193
4916
  }
5194
- }
5195
- if (excludes) {
5196
- for (const item of excludes) {
5197
- addCode(code, [`...t.${key}(`, excludeInnerToCode(item, "t"), "),"]);
4917
+ return acc;
4918
+ }, []);
4919
+ if (!tokens) continue;
4920
+ index.language = language;
4921
+ index.languageColumn = languageColumn;
4922
+ index.tsVector = true;
4923
+ index.columns = [];
4924
+ for (const token of tokens) {
4925
+ if (token.kind === "column") {
4926
+ index.columns.push({
4927
+ column: token.value
4928
+ });
4929
+ } else if (token.kind === "weight") {
4930
+ index.columns[index.columns.length - 1].weight = token.value;
5198
4931
  }
5199
4932
  }
5200
- if (constraints) {
5201
- for (const item of constraints) {
5202
- addCode(code, [
5203
- `...t.${key}(`,
5204
- constraintInnerToCode(item, "t", true),
5205
- "),"
5206
- ]);
5207
- }
4933
+ }
4934
+ (index.exclude ? excludes : indexes).push(index);
4935
+ }
4936
+ result.indexes = indexes;
4937
+ result.excludes = excludes;
4938
+ return result;
4939
+ }
4940
+ const nullsToUndefined = (obj) => {
4941
+ for (const key in obj) {
4942
+ if (obj[key] === null)
4943
+ obj[key] = void 0;
4944
+ }
4945
+ };
4946
+
4947
+ const matchMap = {
4948
+ s: void 0,
4949
+ f: "FULL",
4950
+ p: "PARTIAL"
4951
+ };
4952
+ const fkeyActionMap = {
4953
+ a: void 0,
4954
+ // default
4955
+ r: "RESTRICT",
4956
+ c: "CASCADE",
4957
+ n: "SET NULL",
4958
+ d: "SET DEFAULT"
4959
+ };
4960
+ const makeStructureToAstCtx = (config, currentSchema) => ({
4961
+ snakeCase: config.snakeCase,
4962
+ unsupportedTypes: {},
4963
+ currentSchema,
4964
+ columnSchemaConfig: config.schemaConfig,
4965
+ columnsByType: makeColumnsByType(config.schemaConfig)
4966
+ });
4967
+ const structureToAst = async (ctx, adapter, config) => {
4968
+ const ast = [];
4969
+ const data = await introspectDbSchema(adapter);
4970
+ for (const name of data.schemas) {
4971
+ if (name === "public") continue;
4972
+ ast.push({
4973
+ type: "schema",
4974
+ action: "create",
4975
+ name
4976
+ });
4977
+ }
4978
+ for (const it of data.collations) {
4979
+ ast.push({
4980
+ type: "collation",
4981
+ action: "create",
4982
+ ...it,
4983
+ schema: it.schemaName === ctx.currentSchema ? void 0 : it.schemaName
4984
+ });
4985
+ }
4986
+ const domains = makeDomainsMap(ctx, data);
4987
+ const { schema: migrationsSchema = "public", table: migrationsTable } = getMigrationsSchemaAndTable(config);
4988
+ for (const table of data.tables) {
4989
+ if (table.name === migrationsTable && table.schemaName === migrationsSchema)
4990
+ continue;
4991
+ ast.push(tableToAst(ctx, data, table, "create", domains));
4992
+ }
4993
+ for (const it of data.extensions) {
4994
+ ast.push({
4995
+ type: "extension",
4996
+ action: "create",
4997
+ name: it.name,
4998
+ schema: it.schemaName === ctx.currentSchema ? void 0 : it.schemaName,
4999
+ version: it.version
5000
+ });
5001
+ }
5002
+ for (const it of data.enums) {
5003
+ ast.push({
5004
+ type: "enum",
5005
+ action: "create",
5006
+ name: it.name,
5007
+ schema: it.schemaName === ctx.currentSchema ? void 0 : it.schemaName,
5008
+ values: it.values
5009
+ });
5010
+ }
5011
+ for (const it of data.domains) {
5012
+ ast.push({
5013
+ type: "domain",
5014
+ action: "create",
5015
+ schema: it.schemaName === ctx.currentSchema ? void 0 : it.schemaName,
5016
+ name: it.name,
5017
+ baseType: domains[`${it.schemaName}.${it.name}`]
5018
+ });
5019
+ }
5020
+ for (const table of data.tables) {
5021
+ for (const fkey of data.constraints) {
5022
+ if (fkey.references && fkey.tableName === table.name && fkey.schemaName === table.schemaName && checkIfIsOuterRecursiveFkey(data, table, fkey.references)) {
5023
+ ast.push({
5024
+ ...constraintToAst(ctx, fkey),
5025
+ type: "constraint",
5026
+ action: "create",
5027
+ tableSchema: table.schemaName === ctx.currentSchema ? void 0 : table.schemaName,
5028
+ tableName: fkey.tableName
5029
+ });
5208
5030
  }
5209
5031
  }
5210
- if (ast.comment !== void 0) {
5211
- addCode(code, "}),");
5212
- addCode(result, ");");
5213
- } else {
5214
- addCode(result, "}));");
5032
+ }
5033
+ for (const view of data.views) {
5034
+ ast.push(viewToAst(ctx, data, domains, view));
5035
+ }
5036
+ return ast;
5037
+ };
5038
+ const makeDomainsMap = (ctx, data) => {
5039
+ const domains = {};
5040
+ for (const it of data.domains) {
5041
+ const column = instantiateDbColumn(ctx, data, domains, {
5042
+ schemaName: it.schemaName,
5043
+ name: it.name,
5044
+ type: it.type,
5045
+ typeSchema: it.typeSchema,
5046
+ arrayDims: it.arrayDims,
5047
+ tableName: "",
5048
+ isNullable: it.isNullable,
5049
+ collate: it.collate,
5050
+ default: it.default,
5051
+ typmod: -1
5052
+ });
5053
+ if (it.checks) {
5054
+ column.data.checks = it.checks.map((check) => ({
5055
+ sql: new RawSql([[check]])
5056
+ }));
5057
+ }
5058
+ domains[`${it.schemaName}.${it.name}`] = column;
5059
+ }
5060
+ return domains;
5061
+ };
5062
+ const getDbColumnIsSerial = (item) => {
5063
+ if (item.type === "int2" || item.type === "int4" || item.type === "int8") {
5064
+ const { default: def, schemaName, tableName, name } = item;
5065
+ const seq = `${tableName}_${name}_seq`;
5066
+ if (def && (def === `nextval(${singleQuote(`${seq}`)}::regclass)` || def === `nextval(${singleQuote(`"${seq}"`)}::regclass)` || def === `nextval(${singleQuote(`${schemaName}.${seq}`)}::regclass)` || def === `nextval(${singleQuote(`"${schemaName}".${seq}`)}::regclass)` || def === `nextval(${singleQuote(`${schemaName}."${seq}"`)}::regclass)` || def === `nextval(${singleQuote(`"${schemaName}"."${seq}"`)}::regclass)`)) {
5067
+ return true;
5215
5068
  }
5216
- return result;
5217
- },
5218
- renameType(ast, _, currentSchema) {
5219
- const code = [];
5220
- const kind = ast.kind === "TABLE" ? "Table" : "Type";
5221
- if (ast.from === ast.to) {
5222
- addCode(
5223
- code,
5224
- `await db.change${kind}Schema(${singleQuote(ast.to)}, ${singleQuote(
5225
- ast.fromSchema ?? currentSchema
5226
- )}, ${singleQuote(ast.toSchema ?? currentSchema)});`
5227
- );
5069
+ }
5070
+ return false;
5071
+ };
5072
+ const instantiateDbColumn = (ctx, data, domains, dbColumn) => {
5073
+ var _a, _b;
5074
+ const isSerial = getDbColumnIsSerial(dbColumn);
5075
+ if (isSerial) {
5076
+ dbColumn = { ...dbColumn, default: void 0 };
5077
+ }
5078
+ let column;
5079
+ const col = instantiateColumnByDbType(ctx, dbColumn.type, isSerial, dbColumn);
5080
+ if (col) {
5081
+ column = col;
5082
+ } else {
5083
+ const { typeSchema, type: typeName } = dbColumn;
5084
+ const typeId = typeSchema === "pg_catalog" ? typeName : `${typeSchema}.${typeName}`;
5085
+ const domainColumn = domains[typeId];
5086
+ if (domainColumn) {
5087
+ column = new DomainColumn(
5088
+ ctx.columnSchemaConfig,
5089
+ typeName,
5090
+ typeSchema,
5091
+ dbColumn.extension
5092
+ ).as(domainColumn);
5228
5093
  } else {
5229
- addCode(
5230
- code,
5231
- `await db.rename${kind}(${quoteSchemaTable({
5232
- schema: ast.fromSchema === currentSchema ? void 0 : ast.fromSchema,
5233
- name: ast.from
5234
- })}, ${quoteSchemaTable({
5235
- schema: ast.toSchema === currentSchema ? void 0 : ast.toSchema,
5236
- name: ast.to
5237
- })});`
5094
+ const enumType = data.enums.find(
5095
+ (x) => x.name === typeName && x.schemaName === typeSchema
5238
5096
  );
5097
+ if (enumType) {
5098
+ column = new EnumColumn(
5099
+ ctx.columnSchemaConfig,
5100
+ typeSchema === ctx.currentSchema ? typeName : typeId,
5101
+ enumType.values,
5102
+ ctx.columnSchemaConfig.type
5103
+ );
5104
+ } else {
5105
+ column = new CustomTypeColumn(
5106
+ ctx.columnSchemaConfig,
5107
+ typeName,
5108
+ typeSchema === "pg_catalog" ? void 0 : typeSchema,
5109
+ dbColumn.extension
5110
+ );
5111
+ ((_a = ctx.unsupportedTypes)[_b = dbColumn.type] ?? (_a[_b] = [])).push(
5112
+ `${dbColumn.schemaName}${dbColumn.tableName ? `.${dbColumn.tableName}` : ""}.${dbColumn.name}`
5113
+ );
5114
+ }
5115
+ assignDbDataToColumn(column, dbColumn);
5239
5116
  }
5240
- return code;
5241
- },
5242
- schema(ast) {
5243
- return `await db.${ast.action === "create" ? "createSchema" : "dropSchema"}(${singleQuote(ast.name)});`;
5244
- },
5245
- renameSchema(ast) {
5246
- return `await db.renameSchema(${singleQuote(ast.from)}, ${singleQuote(
5247
- ast.to
5248
- )});`;
5249
- },
5250
- extension(ast) {
5251
- const code = [
5252
- `await db.${ast.action}Extension(${quoteSchemaTable(ast)}`
5253
- ];
5254
- if (ast.version) {
5255
- addCode(code, ", {");
5256
- code.push([`version: ${singleQuote(ast.version)},`], "}");
5117
+ }
5118
+ column.data.name = void 0;
5119
+ if (!column.data.isNullable) column.data.isNullable = void 0;
5120
+ if (dbColumn.arrayDims) {
5121
+ const arr = new ArrayColumn(
5122
+ ctx.columnSchemaConfig,
5123
+ column,
5124
+ ctx.columnSchemaConfig.type
5125
+ );
5126
+ arr.data.isNullable = dbColumn.isNullable;
5127
+ arr.data.arrayDims = dbColumn.arrayDims;
5128
+ column = arr;
5129
+ }
5130
+ return column;
5131
+ };
5132
+ const instantiateColumnByDbType = (ctx, type, isSerial, params) => {
5133
+ let columnFn = ctx.columnsByType[!isSerial ? type : type === "int2" ? "smallserial" : type === "int4" ? "serial" : "bigserial"];
5134
+ if (!columnFn && params.extension === "postgis" && type === "geography" && PostgisGeographyPointColumn.isDefaultPoint(params.typmod)) {
5135
+ columnFn = ctx.columnsByType.geographyDefaultPoint;
5136
+ }
5137
+ return columnFn ? assignDbDataToColumn(columnFn(), params) : void 0;
5138
+ };
5139
+ const tableToAst = (ctx, data, table, action, domains) => {
5140
+ const { schemaName, name: tableName } = table;
5141
+ const tableData = getDbStructureTableData(data, table);
5142
+ const { primaryKey, constraints } = tableData;
5143
+ return {
5144
+ type: "table",
5145
+ action,
5146
+ schema: schemaName === ctx.currentSchema ? void 0 : schemaName,
5147
+ comment: table.comment,
5148
+ name: tableName,
5149
+ shape: makeDbStructureColumnsShape(ctx, data, domains, table, tableData),
5150
+ noPrimaryKey: tableData.primaryKey ? "error" : "ignore",
5151
+ primaryKey: primaryKey && primaryKey.columns.length > 1 ? { ...primaryKey, columns: primaryKey.columns.map(toCamelCase) } : void 0,
5152
+ indexes: indexesOrExcludesToAst(
5153
+ tableName,
5154
+ tableData,
5155
+ "indexes"
5156
+ ),
5157
+ excludes: indexesOrExcludesToAst(
5158
+ tableName,
5159
+ tableData,
5160
+ "excludes"
5161
+ ),
5162
+ constraints: constraints.reduce((acc, it) => {
5163
+ if (it.check && it.references || it.check && it.check.columns?.length !== 1 || it.references && it.references.columns.length !== 1 && !checkIfIsOuterRecursiveFkey(data, table, it.references)) {
5164
+ acc.push(dbConstraintToTableConstraint(ctx, table, it));
5165
+ }
5166
+ return acc;
5167
+ }, [])
5168
+ };
5169
+ };
5170
+ const indexesOrExcludesToAst = (tableName, tableData, key) => {
5171
+ return tableData[key].reduce((acc, item) => {
5172
+ if (item.columns.length > 1 || item.columns.some((it) => "expression" in it)) {
5173
+ const options = makeIndexOrExcludeOptions(tableName, item, key);
5174
+ acc.push({
5175
+ columns: item.columns.map((it, i) => ({
5176
+ with: "exclude" in item && item.exclude ? item.exclude[i] : void 0,
5177
+ ..."expression" in it ? { expression: it.expression } : { column: toCamelCase(it.column) },
5178
+ collate: it.collate,
5179
+ opclass: it.opclass,
5180
+ order: it.order
5181
+ })),
5182
+ options: {
5183
+ ...options,
5184
+ include: item.include?.map(toCamelCase)
5185
+ }
5186
+ });
5257
5187
  }
5258
- addCode(code, ");");
5259
- return code;
5260
- },
5261
- enum(ast, _, currentSchema) {
5262
- return `await db.${ast.action === "create" ? "createEnum" : "dropEnum"}(${quoteSchemaTable(ast, currentSchema)}, [${ast.values.map(singleQuote).join(", ")}]);`;
5263
- },
5264
- enumValues(ast, _, currentSchema) {
5265
- return `await db.${ast.action}EnumValues(${quoteSchemaTable(
5266
- ast,
5267
- currentSchema
5268
- )}, [${ast.values.map(singleQuote).join(", ")}]);`;
5269
- },
5270
- renameEnumValues(ast, config, currentSchema) {
5271
- return `await db.renameEnumValues(${quoteSchemaTable(
5272
- ast,
5273
- currentSchema
5274
- )}, { ${Object.entries(ast.values).map(
5275
- ([from, to]) => `${quoteObjectKey(from, config.snakeCase)}: ${singleQuote(to)}`
5276
- ).join(", ")} });`;
5277
- },
5278
- changeEnumValues(ast, _, currentSchema) {
5279
- return `await db.changeEnumValues(${quoteSchemaTable(
5280
- ast,
5281
- currentSchema
5282
- )}, [${ast.fromValues.map(singleQuote).join(", ")}], [${ast.toValues.map(singleQuote).join(", ")}]);`;
5283
- },
5284
- domain(ast, _, currentSchema) {
5285
- return `await db.${ast.action}Domain(${quoteSchemaTable(
5286
- ast
5287
- )}, (t) => ${ast.baseType.toCode(
5288
- { t: "t", table: ast.name, currentSchema },
5289
- ast.baseType.data.name ?? ""
5290
- )});`;
5291
- },
5292
- collation(ast) {
5293
- const params = [];
5294
- if (ast.locale) params.push(`locale: '${ast.locale}',`);
5295
- if (ast.lcCollate) params.push(`lcCollate: '${ast.lcCollate}',`);
5296
- if (ast.lcCType) params.push(`lcCType: '${ast.lcCType}',`);
5297
- if (ast.provider) params.push(`provider: '${ast.provider}',`);
5298
- if (ast.deterministic) params.push(`deterministic: ${ast.deterministic},`);
5299
- if (ast.version) params.push(`version: '${ast.version}',`);
5300
- return [
5301
- `await db.createCollation(${quoteSchemaTable(ast)}, {`,
5302
- params,
5303
- "});"
5304
- ];
5305
- },
5306
- constraint(ast) {
5307
- const table = quoteSchemaTable({
5308
- schema: ast.tableSchema,
5309
- name: ast.tableName
5310
- });
5311
- if (ast.references) {
5312
- return [
5313
- `await db.addForeignKey(`,
5314
- [`${table},`, ...referencesArgsToCode(ast.references, ast.name, true)],
5315
- ");"
5316
- ];
5188
+ return acc;
5189
+ }, []);
5190
+ };
5191
+ const getDbStructureTableData = (data, { name, schemaName }) => {
5192
+ const filterFn = filterByTableSchema(name, schemaName);
5193
+ const constraints = data.constraints.filter(filterFn);
5194
+ const primaryKey = constraints.find((c) => c.primaryKey);
5195
+ return {
5196
+ primaryKey: primaryKey?.primaryKey ? {
5197
+ columns: primaryKey.primaryKey,
5198
+ name: primaryKey.name === `${name}_pkey` ? void 0 : primaryKey.name
5199
+ } : void 0,
5200
+ indexes: data.indexes.filter(filterFn),
5201
+ excludes: data.excludes.filter(filterFn),
5202
+ constraints
5203
+ };
5204
+ };
5205
+ const filterByTableSchema = (tableName, schemaName) => (x) => x.tableName === tableName && x.schemaName === schemaName;
5206
+ const constraintToAst = (ctx, item) => {
5207
+ const result = {};
5208
+ const { references, check } = item;
5209
+ if (references) {
5210
+ const options = {};
5211
+ result.references = {
5212
+ columns: references.columns,
5213
+ fnOrTable: getReferencesTable(ctx, references),
5214
+ foreignColumns: references.foreignColumns,
5215
+ options
5216
+ };
5217
+ const match = matchMap[references.match];
5218
+ if (match) options.match = match;
5219
+ const onUpdate = fkeyActionMap[references.onUpdate];
5220
+ if (onUpdate) options.onUpdate = onUpdate;
5221
+ const onDelete = fkeyActionMap[references.onDelete];
5222
+ if (onDelete) options.onDelete = onDelete;
5223
+ }
5224
+ if (check) {
5225
+ result.check = raw({ raw: check.expression });
5226
+ }
5227
+ if (item.name && item.name !== getConstraintName(item.tableName, result, ctx.snakeCase)) {
5228
+ result.name = item.name;
5229
+ if (result.references?.options) {
5230
+ result.references.options.name = item.name;
5317
5231
  }
5318
- const check = ast.check;
5319
- return [
5320
- `await db.addCheck(${table}, ${rawSqlToCode(check, "t")}${ast.name ? `, ${singleQuote(ast.name)}` : ""});`
5321
- ];
5322
- },
5323
- renameTableItem(ast) {
5324
- return [
5325
- `await db.rename${ast.kind === "INDEX" ? "Index" : "Constraint"}(${quoteSchemaTable({
5326
- schema: ast.tableSchema,
5327
- name: ast.tableName
5328
- })}, ${singleQuote(ast.from)}, ${singleQuote(ast.to)});`
5329
- ];
5330
- },
5331
- view(ast) {
5332
- const code = [`await db.createView(${quoteSchemaTable(ast)}`];
5333
- const options = [];
5334
- if (ast.options.recursive) options.push("recursive: true,");
5335
- const w = ast.options.with;
5336
- if (w?.checkOption) options.push(`checkOption: '${w.checkOption}',`);
5337
- if (w?.securityBarrier)
5338
- options.push(`securityBarrier: ${w.securityBarrier},`);
5339
- if (w?.securityInvoker)
5340
- options.push(`securityInvoker: ${w.securityInvoker},`);
5341
- if (options.length) {
5342
- addCode(code, ", {");
5343
- code.push(options, "}");
5232
+ }
5233
+ return result;
5234
+ };
5235
+ const getReferencesTable = (ctx, references) => {
5236
+ return references.foreignSchema !== ctx.currentSchema ? `${references.foreignSchema}.${references.foreignTable}` : references.foreignTable;
5237
+ };
5238
+ const isColumnCheck = (it) => {
5239
+ return !it.references && it.check?.columns?.length === 1;
5240
+ };
5241
+ const viewToAst = (ctx, data, domains, view) => {
5242
+ const shape = makeDbStructureColumnsShape(ctx, data, domains, view);
5243
+ const options = {};
5244
+ if (view.isRecursive) options.recursive = true;
5245
+ if (view.with) {
5246
+ const withOptions = {};
5247
+ options.with = withOptions;
5248
+ for (const pair of view.with) {
5249
+ const [key, value] = pair.split("=");
5250
+ withOptions[toCamelCase(key)] = value === "true" ? true : value === "false" ? false : value;
5344
5251
  }
5345
- addCode(code, ", ");
5346
- if (!ast.sql._values) {
5347
- const raw = ast.sql._sql;
5348
- let sql;
5349
- if (typeof raw === "string") {
5350
- sql = raw;
5351
- } else {
5352
- sql = "";
5353
- const parts = raw[0];
5354
- const last = parts.length - 1;
5355
- for (let i = 0; i < last; i++) {
5356
- sql += parts[i] + `\${${raw[i + 1]}}`;
5357
- }
5358
- sql += parts[last];
5252
+ }
5253
+ return {
5254
+ type: "view",
5255
+ action: "create",
5256
+ schema: view.schemaName === ctx.currentSchema ? void 0 : view.schemaName,
5257
+ name: view.name,
5258
+ shape,
5259
+ sql: raw({ raw: view.sql }),
5260
+ options,
5261
+ deps: view.deps
5262
+ };
5263
+ };
5264
+ const makeDbStructureColumnsShape = (ctx, data, domains, table, tableData) => {
5265
+ const shape = {};
5266
+ const checks = tableData ? getDbTableColumnsChecks(tableData) : void 0;
5267
+ for (const item of table.columns) {
5268
+ const [key, column] = dbColumnToAst(
5269
+ ctx,
5270
+ data,
5271
+ domains,
5272
+ table.name,
5273
+ item,
5274
+ table,
5275
+ tableData,
5276
+ checks
5277
+ );
5278
+ shape[key] = column;
5279
+ }
5280
+ return shape;
5281
+ };
5282
+ const getDbTableColumnsChecks = (tableData) => tableData.constraints.reduce((acc, item) => {
5283
+ var _a;
5284
+ if (isColumnCheck(item)) {
5285
+ (acc[_a = item.check.columns[0]] ?? (acc[_a] = [])).push(item.check.expression);
5286
+ }
5287
+ return acc;
5288
+ }, {});
5289
+ const dbColumnToAst = (ctx, data, domains, tableName, item, table, tableData, checks) => {
5290
+ let column = instantiateDbColumn(ctx, data, domains, item);
5291
+ column.data.name = item.name;
5292
+ if (item.identity) {
5293
+ column.data.identity = item.identity;
5294
+ if (!item.identity.always) delete column.data.identity?.always;
5295
+ }
5296
+ if (tableData?.primaryKey?.columns?.length === 1 && tableData?.primaryKey?.columns[0] === item.name) {
5297
+ column = column.primaryKey();
5298
+ }
5299
+ collectColumnIndexesOrExcludes(item, column, tableName, tableData, "indexes");
5300
+ collectColumnIndexesOrExcludes(
5301
+ item,
5302
+ column,
5303
+ tableName,
5304
+ tableData,
5305
+ "excludes"
5306
+ );
5307
+ if (table) {
5308
+ for (const it of data.constraints) {
5309
+ if (it.tableName !== table.name || it.schemaName !== table.schemaName || it.check || it.references?.columns.length !== 1 || it.references.columns[0] !== item.name || checkIfIsOuterRecursiveFkey(data, table, it.references)) {
5310
+ continue;
5359
5311
  }
5360
- addCode(code, backtickQuote(sql));
5361
- } else {
5362
- addCode(code, rawSqlToCode(ast.sql, "db"));
5312
+ const c = dbConstraintToTableConstraint(ctx, table, it);
5313
+ column = column.foreignKey(
5314
+ c.references?.fnOrTable,
5315
+ it.references.foreignColumns[0],
5316
+ c.references?.options
5317
+ );
5363
5318
  }
5364
- addCode(code, ");");
5365
- return code;
5366
5319
  }
5320
+ const columnChecks = checks?.[item.name];
5321
+ if (columnChecks) {
5322
+ column.data.checks = columnChecks.map((check) => ({
5323
+ sql: new RawSql([[check]])
5324
+ }));
5325
+ }
5326
+ const camelCaseName = toCamelCase(item.name);
5327
+ if (ctx.snakeCase) {
5328
+ const snakeCaseName = toSnakeCase(camelCaseName);
5329
+ if (snakeCaseName !== item.name) column.data.name = item.name;
5330
+ } else if (camelCaseName !== item.name) {
5331
+ column.data.name = item.name;
5332
+ }
5333
+ return [camelCaseName, column];
5367
5334
  };
5368
- const isTimestamp = (column, type) => {
5369
- if (!column) return false;
5370
- const { default: def } = column.data;
5371
- return Boolean(
5372
- column instanceof type && !column.data.isNullable && def && typeof def === "object" && isRawSQL(def) && (typeof def._sql === "object" ? def._sql[0][0] : def._sql) === "now()"
5335
+ const collectColumnIndexesOrExcludes = (dbColumn, column, tableName, tableData, key) => {
5336
+ var _a;
5337
+ const items = tableData?.[key];
5338
+ if (!items) return;
5339
+ const columnItems = items.filter(
5340
+ (it) => it.columns.length === 1 && "column" in it.columns[0] && it.columns[0].column === dbColumn.name
5373
5341
  );
5342
+ for (const item of columnItems) {
5343
+ const columnOptions = item.columns[0];
5344
+ const { name, ...itemOptions } = makeIndexOrExcludeOptions(
5345
+ tableName,
5346
+ item,
5347
+ key
5348
+ );
5349
+ ((_a = column.data)[key] ?? (_a[key] = [])).push({
5350
+ with: "exclude" in item && item.exclude ? item.exclude[0] : void 0,
5351
+ options: {
5352
+ name,
5353
+ collate: columnOptions.collate,
5354
+ opclass: columnOptions.opclass,
5355
+ order: columnOptions.order,
5356
+ ...itemOptions
5357
+ }
5358
+ });
5359
+ }
5374
5360
  };
5375
- const getHasTimestamps = (createdAt, updatedAt) => {
5376
- const timestamps = getTimestampsInfo(createdAt, updatedAt, TimestampTZColumn);
5377
- const timestampsNoTZ = getTimestampsInfo(
5378
- createdAt,
5379
- updatedAt,
5380
- TimestampColumn
5381
- );
5382
- return {
5383
- hasTZTimestamps: timestamps,
5384
- hasAnyTimestamps: timestamps || timestampsNoTZ
5361
+ const dbConstraintToTableConstraint = (ctx, table, item) => {
5362
+ const { references, check } = item;
5363
+ const constraint = {
5364
+ references: references ? {
5365
+ columns: references.columns,
5366
+ fnOrTable: getReferencesTable(ctx, references),
5367
+ foreignColumns: references.foreignColumns,
5368
+ options: {
5369
+ match: matchMap[references.match],
5370
+ onUpdate: fkeyActionMap[references.onUpdate],
5371
+ onDelete: fkeyActionMap[references.onDelete]
5372
+ }
5373
+ } : void 0,
5374
+ check: check ? raw({ raw: check.expression }) : void 0
5385
5375
  };
5376
+ const name = item.name && item.name !== getConstraintName(table.name, constraint, ctx.snakeCase) ? item.name : void 0;
5377
+ if (name) {
5378
+ constraint.name = name;
5379
+ if (constraint.references?.options) {
5380
+ constraint.references.options.name = name;
5381
+ }
5382
+ }
5383
+ return constraint;
5386
5384
  };
5387
- const getTimestampsInfo = (createdAt, updatedAt, type) => {
5388
- return isTimestamp(createdAt, type) && isTimestamp(updatedAt, type) && (!createdAt?.data.name || createdAt?.data.name === "created_at") && (!updatedAt?.data.name || updatedAt?.data.name === "updated_at");
5385
+ const makeIndexOrExcludeOptions = (tableName, index, key) => {
5386
+ return {
5387
+ name: index.name !== (key === "indexes" ? getIndexName : getExcludeName)(
5388
+ tableName,
5389
+ index.columns
5390
+ ) ? index.name : void 0,
5391
+ using: index.using === "btree" ? void 0 : index.using,
5392
+ unique: index.unique || void 0,
5393
+ include: index.include,
5394
+ nullsNotDistinct: index.nullsNotDistinct || void 0,
5395
+ with: index.with,
5396
+ tablespace: index.tablespace,
5397
+ where: index.where
5398
+ };
5389
5399
  };
5390
- const timestampsToCode = ({ hasTZTimestamps }) => {
5391
- const key = hasTZTimestamps ? "timestamps" : "timestampsNoTZ";
5392
- return `t.${key}()`;
5400
+ const checkIfIsOuterRecursiveFkey = (data, table, references) => {
5401
+ const referencesId = `${references.foreignSchema}.${references.foreignTable}`;
5402
+ const tableId = `${table.schemaName}.${table.name}`;
5403
+ for (const other of data.tables) {
5404
+ const id = `${other.schemaName}.${other.name}`;
5405
+ if (referencesId === id) {
5406
+ for (const c of data.constraints) {
5407
+ if (c.tableName === other.name && c.schemaName === other.schemaName && c.references?.foreignTable === table.name && c.references.foreignSchema === table.schemaName && tableId < id) {
5408
+ return true;
5409
+ }
5410
+ }
5411
+ break;
5412
+ }
5413
+ }
5414
+ return false;
5393
5415
  };
5394
5416
 
5395
5417
  const pullDbStructure = async (adapter, config) => {
5396
- const currentSchema = adapter.schema || "public";
5418
+ const currentSchema = adapter.searchPath || "public";
5397
5419
  const ctx = makeStructureToAstCtx(config, currentSchema);
5398
5420
  const ast = await structureToAst(ctx, adapter, config);
5399
5421
  const result = astToMigration(currentSchema, config, ast);
@@ -5885,5 +5907,5 @@ const makeMigrateAdapter = (config) => {
5885
5907
  };
5886
5908
  };
5887
5909
 
5888
- export { RakeDbError, astToMigration, concatSchemaAndName, createMigrationInterface, dbColumnToAst, encodeColumnDefault, getConstraintName, getDbStructureTableData, getDbTableColumnsChecks, getExcludeName, getIndexName, getSchemaAndTableFromName, instantiateDbColumn, introspectDbSchema, makeChange, makeDomainsMap, makeFileVersion, makeMigrateAdapter, makeStructureToAstCtx, migrate, migrateAndClose, migrateFiles, migrationConfigDefaults, processRakeDbConfig, promptSelect, rakeDbCommands, rakeDbWithAdapters, runCommand, saveMigratedVersion, structureToAst, tableToAst, writeMigrationFile };
5910
+ export { RakeDbError, astToMigration, concatSchemaAndName, createMigrationInterface, dbColumnToAst, encodeColumnDefault, getConstraintName, getDbStructureTableData, getDbTableColumnsChecks, getExcludeName, getIndexName, getMigrationsSchemaAndTable, getSchemaAndTableFromName, instantiateDbColumn, introspectDbSchema, makeChange, makeDomainsMap, makeFileVersion, makeMigrateAdapter, makeStructureToAstCtx, migrate, migrateAndClose, migrateFiles, migrationConfigDefaults, processRakeDbConfig, promptSelect, rakeDbCommands, rakeDbWithAdapters, runCommand, saveMigratedVersion, structureToAst, tableToAst, writeMigrationFile };
5889
5911
  //# sourceMappingURL=index.mjs.map