rake-db 2.30.8 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +161 -87
- package/dist/index.js +987 -922
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +871 -806
- package/dist/index.mjs.map +1 -1
- package/dist/node-postgres.d.ts +1 -1
- package/dist/node-postgres.js +2 -2
- package/dist/node-postgres.js.map +1 -1
- package/dist/node-postgres.mjs +1 -1
- package/dist/node-postgres.mjs.map +1 -1
- package/dist/postgres-js.d.ts +1 -1
- package/dist/postgres-js.js +2 -2
- package/dist/postgres-js.js.map +1 -1
- package/dist/postgres-js.mjs +1 -1
- package/dist/postgres-js.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,247 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { singleQuote, makeColumnTypes, defaultSchemaConfig, 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, getStackTrace } from 'pqb/internal';
|
|
2
2
|
import path, { join } from 'path';
|
|
3
3
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
4
4
|
import fs, { mkdir, writeFile, readdir, stat, readFile } from 'fs/promises';
|
|
5
|
-
|
|
6
|
-
const ESC = "\x1B";
|
|
7
|
-
const CSI = `${ESC}[`;
|
|
8
|
-
const cursorShow = `${CSI}?25h`;
|
|
9
|
-
const cursorHide = `${CSI}?25l`;
|
|
10
|
-
const { stdin, stdout } = process;
|
|
11
|
-
const visibleChars = (s) => s.replace(
|
|
12
|
-
// eslint-disable-next-line no-control-regex
|
|
13
|
-
/[\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,
|
|
14
|
-
""
|
|
15
|
-
).length;
|
|
16
|
-
const clear = (text) => {
|
|
17
|
-
const rows = text.split(/\r?\n/).reduce(
|
|
18
|
-
(rows2, line) => rows2 + 1 + Math.floor(Math.max(visibleChars(line) - 1, 0) / stdout.columns),
|
|
19
|
-
0
|
|
20
|
-
);
|
|
21
|
-
let clear2 = "";
|
|
22
|
-
for (let i = 0; i < rows; i++) {
|
|
23
|
-
clear2 += `${CSI}2K`;
|
|
24
|
-
if (i < rows - 1) {
|
|
25
|
-
clear2 += `${CSI}${i < rows - 1 ? "1A" : "G"}`;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return clear2;
|
|
29
|
-
};
|
|
30
|
-
const prompt = async ({
|
|
31
|
-
render,
|
|
32
|
-
onKeyPress,
|
|
33
|
-
validate,
|
|
34
|
-
value,
|
|
35
|
-
cursor: showCursor
|
|
36
|
-
}) => {
|
|
37
|
-
stdin.resume();
|
|
38
|
-
if (stdin.isTTY) stdin.setRawMode(true);
|
|
39
|
-
stdin.setEncoding("utf-8");
|
|
40
|
-
if (!showCursor) stdout.write(cursorHide);
|
|
41
|
-
return new Promise((res) => {
|
|
42
|
-
let prevText;
|
|
43
|
-
const ctx = {
|
|
44
|
-
value,
|
|
45
|
-
submitted: false,
|
|
46
|
-
render() {
|
|
47
|
-
let text = (ctx.submitted ? colors.greenBold("\u2714") : colors.yellowBold("?")) + " " + render(ctx);
|
|
48
|
-
if (ctx.submitted) text += "\n";
|
|
49
|
-
stdout.write(prevText ? clear(prevText) + "\r" + text : text);
|
|
50
|
-
prevText = text;
|
|
51
|
-
},
|
|
52
|
-
submit(value2) {
|
|
53
|
-
if (value2 !== void 0) ctx.value = value2;
|
|
54
|
-
if (ctx.value === void 0 || validate && !validate?.(ctx)) return;
|
|
55
|
-
ctx.submitted = true;
|
|
56
|
-
ctx.render();
|
|
57
|
-
close();
|
|
58
|
-
res(ctx.value);
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
const close = () => {
|
|
62
|
-
if (!showCursor) stdout.write(cursorShow);
|
|
63
|
-
if (stdin.isTTY) stdin.setRawMode(false);
|
|
64
|
-
stdin.off("data", keypress);
|
|
65
|
-
stdin.pause();
|
|
66
|
-
};
|
|
67
|
-
const keypress = (s) => {
|
|
68
|
-
if (s === "" || s === "") {
|
|
69
|
-
close?.();
|
|
70
|
-
process.exit(0);
|
|
71
|
-
}
|
|
72
|
-
if (s === "\r" || s === "\n" || s === "\r\n") {
|
|
73
|
-
ctx.submit();
|
|
74
|
-
} else {
|
|
75
|
-
onKeyPress(ctx, s);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
stdin.on("data", keypress);
|
|
79
|
-
ctx.render();
|
|
80
|
-
});
|
|
81
|
-
};
|
|
82
|
-
const defaultActive = (s) => `${colors.blueBold("\u276F")} ${s}`;
|
|
83
|
-
const defaultInactive = (s) => ` ${s}`;
|
|
84
|
-
const promptSelect = ({
|
|
85
|
-
message,
|
|
86
|
-
options,
|
|
87
|
-
active = defaultActive,
|
|
88
|
-
inactive = defaultInactive
|
|
89
|
-
}) => prompt({
|
|
90
|
-
value: 0,
|
|
91
|
-
render(ctx) {
|
|
92
|
-
let text = `${message} ${colors.pale(
|
|
93
|
-
"Use arrows or jk. Press enter to submit."
|
|
94
|
-
)}
|
|
95
|
-
`;
|
|
96
|
-
for (let i = 0; i < options.length; i++) {
|
|
97
|
-
text += (ctx.value === i ? active : inactive)(options[i]) + "\n";
|
|
98
|
-
}
|
|
99
|
-
return text;
|
|
100
|
-
},
|
|
101
|
-
onKeyPress(ctx, s) {
|
|
102
|
-
ctx.value = s === "\x1B[H" ? 0 : s === "\x1B[F" ? options.length - 1 : s === "\x1B[A" || s === "k" ? ctx.value === 0 ? options.length - 1 : ctx.value - 1 : s === "\x1B[B" || s === "j" || s === " " ? ctx.value === options.length - 1 ? 0 : ctx.value + 1 : ctx.value;
|
|
103
|
-
ctx.render();
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
const promptConfirm = ({
|
|
107
|
-
message
|
|
108
|
-
}) => prompt({
|
|
109
|
-
value: true,
|
|
110
|
-
render(ctx) {
|
|
111
|
-
return `${colors.bright(message)}
|
|
112
|
-
${ctx.submitted ? `> ${ctx.value ? colors.greenBold("Yes") : colors.yellowBold("No")}` : colors.pale(`> (Y/n)`)}
|
|
113
|
-
`;
|
|
114
|
-
},
|
|
115
|
-
onKeyPress(ctx, s) {
|
|
116
|
-
let ok;
|
|
117
|
-
if (s === "y" || s === "Y") ok = true;
|
|
118
|
-
else if (s === "n" || s === "N") ok = false;
|
|
119
|
-
if (ok !== void 0) {
|
|
120
|
-
ctx.submit(ok);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
const promptText = ({
|
|
125
|
-
message,
|
|
126
|
-
default: def = "",
|
|
127
|
-
password,
|
|
128
|
-
min
|
|
129
|
-
}) => {
|
|
130
|
-
let showDefault = true;
|
|
131
|
-
let x = 0;
|
|
132
|
-
const renderValue = (ctx) => password ? "*".repeat(ctx.value.length) : ctx.value;
|
|
133
|
-
return prompt({
|
|
134
|
-
value: def,
|
|
135
|
-
cursor: true,
|
|
136
|
-
validate: (ctx) => !min || ctx.value.length >= min,
|
|
137
|
-
render(ctx) {
|
|
138
|
-
let text = `${colors.bright(message)}
|
|
139
|
-
> ${ctx.submitted ? renderValue(ctx) : showDefault ? colors.pale(def) + "\b".repeat(def.length) : ctx.value}`;
|
|
140
|
-
if (ctx.submitted) text += "\n";
|
|
141
|
-
return text;
|
|
142
|
-
},
|
|
143
|
-
onKeyPress(ctx, s) {
|
|
144
|
-
let value = showDefault ? "" : ctx.value;
|
|
145
|
-
if (s === "\x1B[D" && x > 0) {
|
|
146
|
-
x--;
|
|
147
|
-
stdout.write("\b");
|
|
148
|
-
} else if (s === "\x1B[C" && x < value.length) {
|
|
149
|
-
stdout.write(value[x]);
|
|
150
|
-
x++;
|
|
151
|
-
}
|
|
152
|
-
if (s !== "\x7F" && s !== "\x1B[3~" && !visibleChars(s)) return;
|
|
153
|
-
if (showDefault) {
|
|
154
|
-
showDefault = false;
|
|
155
|
-
stdout.write(" ".repeat(def.length) + "\b".repeat(def.length));
|
|
156
|
-
}
|
|
157
|
-
const prev = value;
|
|
158
|
-
const prevX = x;
|
|
159
|
-
if (s === "\x7F") {
|
|
160
|
-
if (x > 0) {
|
|
161
|
-
value = value.slice(0, x - 1) + value.slice(x);
|
|
162
|
-
x--;
|
|
163
|
-
}
|
|
164
|
-
} else if (s === "\x1B[3~") {
|
|
165
|
-
if (x < value.length) {
|
|
166
|
-
value = value.slice(0, x) + value.slice(x + 1);
|
|
167
|
-
}
|
|
168
|
-
} else {
|
|
169
|
-
value = value.slice(0, x) + s + value.slice(x);
|
|
170
|
-
x++;
|
|
171
|
-
}
|
|
172
|
-
ctx.value = value;
|
|
173
|
-
const spaces = prev.length - value.length;
|
|
174
|
-
stdout.write(
|
|
175
|
-
"\b".repeat(prevX) + renderValue(ctx) + (spaces > 0 ? " ".repeat(spaces) + "\b".repeat(spaces) : "") + "\b".repeat(value.length - x)
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
const getMaybeTransactionAdapter = (db) => "$getAdapter" in db ? db.$getAdapter() : db;
|
|
182
|
-
const runSqlInSavePoint = async (db, sql, code) => {
|
|
183
|
-
const adapter = getMaybeTransactionAdapter(db);
|
|
184
|
-
try {
|
|
185
|
-
await adapter.query(
|
|
186
|
-
adapter.isInTransaction() ? `SAVEPOINT s; ${sql}; RELEASE SAVEPOINT s` : sql
|
|
187
|
-
);
|
|
188
|
-
return "done";
|
|
189
|
-
} catch (err) {
|
|
190
|
-
if (err.code === code) {
|
|
191
|
-
if (adapter.isInTransaction()) {
|
|
192
|
-
await adapter.query(`ROLLBACK TO SAVEPOINT s`);
|
|
193
|
-
}
|
|
194
|
-
return "already";
|
|
195
|
-
}
|
|
196
|
-
throw err;
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
class CreateOrDropError extends Error {
|
|
201
|
-
constructor(message, status, cause) {
|
|
202
|
-
super(message);
|
|
203
|
-
this.status = status;
|
|
204
|
-
this.cause = cause;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
const createDatabase = async (db, {
|
|
208
|
-
database,
|
|
209
|
-
owner
|
|
210
|
-
}) => {
|
|
211
|
-
return createOrDrop(
|
|
212
|
-
db,
|
|
213
|
-
`CREATE DATABASE "${database}"${owner ? ` OWNER "${owner}"` : ""}`
|
|
214
|
-
);
|
|
215
|
-
};
|
|
216
|
-
const dropDatabase = async (db, { database }) => {
|
|
217
|
-
return createOrDrop(db, `DROP DATABASE "${database}"`);
|
|
218
|
-
};
|
|
219
|
-
const createOrDrop = async (db, sql) => {
|
|
220
|
-
try {
|
|
221
|
-
const adapter = getMaybeTransactionAdapter(db);
|
|
222
|
-
await adapter.query(sql);
|
|
223
|
-
return "done";
|
|
224
|
-
} catch (error) {
|
|
225
|
-
const err = error;
|
|
226
|
-
if (typeof err.message === "string" && err.message.includes("sslmode=require")) {
|
|
227
|
-
throw new CreateOrDropError("SSL required", "ssl-required", err);
|
|
228
|
-
}
|
|
229
|
-
if (err.code === "42P04" || err.code === "3D000") {
|
|
230
|
-
return "already";
|
|
231
|
-
}
|
|
232
|
-
if (err.code === "42501") {
|
|
233
|
-
throw new CreateOrDropError("Insufficient privilege", "forbidden", err);
|
|
234
|
-
}
|
|
235
|
-
if (typeof err.message === "string" && err.message.includes("password authentication failed")) {
|
|
236
|
-
throw new CreateOrDropError("Authentication failed", "auth-failed", err);
|
|
237
|
-
}
|
|
238
|
-
throw err;
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
const createSchema$1 = async (db, sql) => runSqlInSavePoint(db, `CREATE SCHEMA ${sql}`, "42P06");
|
|
242
|
-
const dropSchema = async (db, sql) => runSqlInSavePoint(db, `DROP SCHEMA ${sql}`, "3F000");
|
|
243
|
-
const createTable$1 = async (db, sql) => runSqlInSavePoint(db, `CREATE TABLE ${sql}`, "42P07");
|
|
244
|
-
const dropTable = async (db, sql) => runSqlInSavePoint(db, `DROP TABLE ${sql}`, "42P01");
|
|
5
|
+
import path$1 from 'node:path';
|
|
245
6
|
|
|
246
7
|
const RAKE_DB_LOCK_KEY = "8582141715823621641";
|
|
247
8
|
const getFirstWordAndRest = (input) => {
|
|
@@ -330,10 +91,13 @@ const getCliParam = (args, name) => {
|
|
|
330
91
|
return;
|
|
331
92
|
};
|
|
332
93
|
|
|
333
|
-
const
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
94
|
+
const createMigrationChangeFn = (config) => {
|
|
95
|
+
const conf = config.columnTypes ? config : { columnTypes: makeColumnTypes(defaultSchemaConfig) };
|
|
96
|
+
return (fn) => {
|
|
97
|
+
const change = { fn, config: conf };
|
|
98
|
+
pushChange(change);
|
|
99
|
+
return change;
|
|
100
|
+
};
|
|
337
101
|
};
|
|
338
102
|
let currentChanges = [];
|
|
339
103
|
const clearChanges = () => {
|
|
@@ -750,7 +514,7 @@ class RakeDbError extends Error {
|
|
|
750
514
|
class NoPrimaryKey extends RakeDbError {
|
|
751
515
|
}
|
|
752
516
|
|
|
753
|
-
const createTable = async (migration, up, tableName, first, second, third) => {
|
|
517
|
+
const createTable$1 = async (migration, up, tableName, first, second, third) => {
|
|
754
518
|
let options;
|
|
755
519
|
let fn;
|
|
756
520
|
let dataFn;
|
|
@@ -1979,27 +1743,37 @@ const createMigrationInterface = (tx, up, config) => {
|
|
|
1979
1743
|
);
|
|
1980
1744
|
};
|
|
1981
1745
|
Object.assign(adapter, { silentQuery: query, silentArrays: arrays });
|
|
1982
|
-
const
|
|
1983
|
-
|
|
1984
|
-
columnTypes: config.columnTypes
|
|
1985
|
-
});
|
|
1986
|
-
const { prototype: proto } = Migration;
|
|
1987
|
-
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
1988
|
-
db[key] = proto[key];
|
|
1989
|
-
}
|
|
1990
|
-
return Object.assign(db, {
|
|
1746
|
+
const dbPerColumnTypes = /* @__PURE__ */ new Map();
|
|
1747
|
+
return {
|
|
1991
1748
|
adapter,
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1749
|
+
getDb(columnTypes) {
|
|
1750
|
+
let db = dbPerColumnTypes.get(columnTypes);
|
|
1751
|
+
if (!db) {
|
|
1752
|
+
db = createDbWithAdapter({
|
|
1753
|
+
adapter,
|
|
1754
|
+
columnTypes
|
|
1755
|
+
});
|
|
1756
|
+
const { prototype: proto } = Migration;
|
|
1757
|
+
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
1758
|
+
db[key] = proto[key];
|
|
1759
|
+
}
|
|
1760
|
+
return Object.assign(db, {
|
|
1761
|
+
adapter,
|
|
1762
|
+
log,
|
|
1763
|
+
up,
|
|
1764
|
+
options: config
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
return db;
|
|
1768
|
+
}
|
|
1769
|
+
};
|
|
1996
1770
|
};
|
|
1997
1771
|
class Migration {
|
|
1998
1772
|
createTable(tableName, first, second, third) {
|
|
1999
|
-
return createTable(this, this.up, tableName, first, second, third);
|
|
1773
|
+
return createTable$1(this, this.up, tableName, first, second, third);
|
|
2000
1774
|
}
|
|
2001
1775
|
dropTable(tableName, first, second, third) {
|
|
2002
|
-
return createTable(this, !this.up, tableName, first, second, third);
|
|
1776
|
+
return createTable$1(this, !this.up, tableName, first, second, third);
|
|
2003
1777
|
}
|
|
2004
1778
|
changeTable(tableName, cbOrOptions, cb) {
|
|
2005
1779
|
const [fn, options] = typeof cbOrOptions === "function" ? [cbOrOptions, {}] : [cb, cbOrOptions];
|
|
@@ -2332,7 +2106,7 @@ class Migration {
|
|
|
2332
2106
|
* @param schemaName - name of the schema
|
|
2333
2107
|
*/
|
|
2334
2108
|
createSchema(schemaName) {
|
|
2335
|
-
return createSchema(this, this.up, schemaName);
|
|
2109
|
+
return createSchema$1(this, this.up, schemaName);
|
|
2336
2110
|
}
|
|
2337
2111
|
/**
|
|
2338
2112
|
* Renames a database schema, renames it backwards on roll back.
|
|
@@ -2359,7 +2133,7 @@ class Migration {
|
|
|
2359
2133
|
* @param schemaName - name of the schema
|
|
2360
2134
|
*/
|
|
2361
2135
|
dropSchema(schemaName) {
|
|
2362
|
-
return createSchema(this, !this.up, schemaName);
|
|
2136
|
+
return createSchema$1(this, !this.up, schemaName);
|
|
2363
2137
|
}
|
|
2364
2138
|
/**
|
|
2365
2139
|
* `createExtension` creates a database extension, and removes it on rollback.
|
|
@@ -2920,7 +2694,7 @@ const addCheck = (migration, up, tableName, check) => {
|
|
|
2920
2694
|
...t.add(t.check(check))
|
|
2921
2695
|
}));
|
|
2922
2696
|
};
|
|
2923
|
-
const createSchema = async (migration, up, name) => {
|
|
2697
|
+
const createSchema$1 = async (migration, up, name) => {
|
|
2924
2698
|
const ast = {
|
|
2925
2699
|
type: "schema",
|
|
2926
2700
|
action: up ? "create" : "drop",
|
|
@@ -3406,7 +3180,7 @@ const getMigrations = async (ctx, config, up, allowDuplicates, getVersion = getM
|
|
|
3406
3180
|
function getMigrationsFromConfig(config, allowDuplicates, getVersion = getMigrationVersionOrThrow) {
|
|
3407
3181
|
const result = [];
|
|
3408
3182
|
const versions = {};
|
|
3409
|
-
const { migrations
|
|
3183
|
+
const { migrations } = config;
|
|
3410
3184
|
for (const key in migrations) {
|
|
3411
3185
|
const version = getVersion(config, path.basename(key));
|
|
3412
3186
|
if (versions[version] && !allowDuplicates) {
|
|
@@ -3416,7 +3190,7 @@ function getMigrationsFromConfig(config, allowDuplicates, getVersion = getMigrat
|
|
|
3416
3190
|
}
|
|
3417
3191
|
versions[version] = key;
|
|
3418
3192
|
result.push({
|
|
3419
|
-
path:
|
|
3193
|
+
path: key,
|
|
3420
3194
|
version,
|
|
3421
3195
|
load: migrations[key]
|
|
3422
3196
|
});
|
|
@@ -3466,7 +3240,7 @@ async function getMigrationsFromFiles(config, allowDuplicates, getVersion = getM
|
|
|
3466
3240
|
}
|
|
3467
3241
|
data.renameTo = {
|
|
3468
3242
|
to: config.migrationId,
|
|
3469
|
-
map: () => renameMigrationsMap(
|
|
3243
|
+
map: () => renameMigrationsMap(migrationsPath, file.name)
|
|
3470
3244
|
};
|
|
3471
3245
|
return data;
|
|
3472
3246
|
} else {
|
|
@@ -3505,8 +3279,8 @@ Run \`**db command** rebase\` to reorganize files with duplicated versions.`
|
|
|
3505
3279
|
result.migrations.sort(sortMigrationsAsc);
|
|
3506
3280
|
return result;
|
|
3507
3281
|
}
|
|
3508
|
-
const renameMigrationsMap = async (
|
|
3509
|
-
const filePath = path.join(
|
|
3282
|
+
const renameMigrationsMap = async (migrationsPath, fileName) => {
|
|
3283
|
+
const filePath = path.join(migrationsPath, fileName);
|
|
3510
3284
|
const json = await fs.readFile(filePath, "utf-8");
|
|
3511
3285
|
let data;
|
|
3512
3286
|
try {
|
|
@@ -3557,10 +3331,75 @@ function getDigitsPrefix(name) {
|
|
|
3557
3331
|
return value;
|
|
3558
3332
|
}
|
|
3559
3333
|
|
|
3560
|
-
const
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3334
|
+
const getMaybeTransactionAdapter = (db) => "$getAdapter" in db ? db.$getAdapter() : db;
|
|
3335
|
+
const runSqlInSavePoint = async (db, sql, code) => {
|
|
3336
|
+
const adapter = getMaybeTransactionAdapter(db);
|
|
3337
|
+
try {
|
|
3338
|
+
await adapter.query(
|
|
3339
|
+
adapter.isInTransaction() ? `SAVEPOINT s; ${sql}; RELEASE SAVEPOINT s` : sql
|
|
3340
|
+
);
|
|
3341
|
+
return "done";
|
|
3342
|
+
} catch (err) {
|
|
3343
|
+
if (err.code === code) {
|
|
3344
|
+
if (adapter.isInTransaction()) {
|
|
3345
|
+
await adapter.query(`ROLLBACK TO SAVEPOINT s`);
|
|
3346
|
+
}
|
|
3347
|
+
return "already";
|
|
3348
|
+
}
|
|
3349
|
+
throw err;
|
|
3350
|
+
}
|
|
3351
|
+
};
|
|
3352
|
+
|
|
3353
|
+
class CreateOrDropError extends Error {
|
|
3354
|
+
constructor(message, status, cause) {
|
|
3355
|
+
super(message);
|
|
3356
|
+
this.status = status;
|
|
3357
|
+
this.cause = cause;
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
const createDatabase = async (db, {
|
|
3361
|
+
database,
|
|
3362
|
+
owner
|
|
3363
|
+
}) => {
|
|
3364
|
+
return createOrDrop(
|
|
3365
|
+
db,
|
|
3366
|
+
`CREATE DATABASE "${database}"${owner ? ` OWNER "${owner}"` : ""}`
|
|
3367
|
+
);
|
|
3368
|
+
};
|
|
3369
|
+
const dropDatabase = async (db, { database }) => {
|
|
3370
|
+
return createOrDrop(db, `DROP DATABASE "${database}"`);
|
|
3371
|
+
};
|
|
3372
|
+
const createOrDrop = async (db, sql) => {
|
|
3373
|
+
try {
|
|
3374
|
+
const adapter = getMaybeTransactionAdapter(db);
|
|
3375
|
+
await adapter.query(sql);
|
|
3376
|
+
return "done";
|
|
3377
|
+
} catch (error) {
|
|
3378
|
+
const err = error;
|
|
3379
|
+
if (typeof err.message === "string" && err.message.includes("sslmode=require")) {
|
|
3380
|
+
throw new CreateOrDropError("SSL required", "ssl-required", err);
|
|
3381
|
+
}
|
|
3382
|
+
if (err.code === "42P04" || err.code === "3D000") {
|
|
3383
|
+
return "already";
|
|
3384
|
+
}
|
|
3385
|
+
if (err.code === "42501") {
|
|
3386
|
+
throw new CreateOrDropError("Insufficient privilege", "forbidden", err);
|
|
3387
|
+
}
|
|
3388
|
+
if (typeof err.message === "string" && err.message.includes("password authentication failed")) {
|
|
3389
|
+
throw new CreateOrDropError("Authentication failed", "auth-failed", err);
|
|
3390
|
+
}
|
|
3391
|
+
throw err;
|
|
3392
|
+
}
|
|
3393
|
+
};
|
|
3394
|
+
const createSchema = async (db, sql) => runSqlInSavePoint(db, `CREATE SCHEMA ${sql}`, "42P06");
|
|
3395
|
+
const dropSchema = async (db, sql) => runSqlInSavePoint(db, `DROP SCHEMA ${sql}`, "3F000");
|
|
3396
|
+
const createTable = async (db, sql) => runSqlInSavePoint(db, `CREATE TABLE ${sql}`, "42P07");
|
|
3397
|
+
const dropTable = async (db, sql) => runSqlInSavePoint(db, `DROP TABLE ${sql}`, "42P01");
|
|
3398
|
+
|
|
3399
|
+
const saveMigratedVersion = async (db, version, name, config) => {
|
|
3400
|
+
await db.silentArrays(
|
|
3401
|
+
`INSERT INTO ${migrationsSchemaTableSql(
|
|
3402
|
+
db,
|
|
3564
3403
|
config
|
|
3565
3404
|
)}(version, name) VALUES ($1, $2)`,
|
|
3566
3405
|
[version, name]
|
|
@@ -3570,12 +3409,12 @@ const createMigrationsSchemaAndTable = async (db, config) => {
|
|
|
3570
3409
|
const adapter = getMaybeTransactionAdapter(db);
|
|
3571
3410
|
const { schema, table } = getMigrationsSchemaAndTable(adapter, config);
|
|
3572
3411
|
if (schema) {
|
|
3573
|
-
const res2 = await createSchema
|
|
3412
|
+
const res2 = await createSchema(db, schema);
|
|
3574
3413
|
if (res2 === "done") {
|
|
3575
3414
|
config.logger?.log(`Created schema "${schema}"`);
|
|
3576
3415
|
}
|
|
3577
3416
|
}
|
|
3578
|
-
const res = await createTable
|
|
3417
|
+
const res = await createTable(
|
|
3579
3418
|
db,
|
|
3580
3419
|
`${schema ? `"${schema}"."${table}"` : `"${table}"`} (version TEXT NOT NULL, name TEXT NOT NULL)`
|
|
3581
3420
|
);
|
|
@@ -3600,53 +3439,62 @@ const deleteMigratedVersion = async (adapter, version, name, config) => {
|
|
|
3600
3439
|
class NoMigrationsTableError extends Error {
|
|
3601
3440
|
}
|
|
3602
3441
|
const getMigratedVersionsMap = async (ctx, adapter, config, renameTo) => {
|
|
3442
|
+
const table = migrationsSchemaTableSql(adapter, config);
|
|
3443
|
+
const inTransaction = "isInTransaction" in adapter && adapter.isInTransaction();
|
|
3444
|
+
let result;
|
|
3603
3445
|
try {
|
|
3604
|
-
|
|
3605
|
-
|
|
3446
|
+
if (inTransaction) {
|
|
3447
|
+
await adapter.query(`SAVEPOINT check_migrations_table`);
|
|
3448
|
+
}
|
|
3449
|
+
result = await adapter.arrays(
|
|
3606
3450
|
`SELECT * FROM ${table} ORDER BY version`
|
|
3607
3451
|
);
|
|
3608
|
-
if (
|
|
3609
|
-
|
|
3610
|
-
const map = {};
|
|
3611
|
-
for (const item of migrations) {
|
|
3612
|
-
const name = path.basename(item.path);
|
|
3613
|
-
map[item.version] = name.slice(getDigitsPrefix(name).length + 1);
|
|
3614
|
-
}
|
|
3615
|
-
for (const row of result.rows) {
|
|
3616
|
-
const [version] = row;
|
|
3617
|
-
const name = map[version];
|
|
3618
|
-
if (!name) {
|
|
3619
|
-
throw new Error(
|
|
3620
|
-
`Migration for version ${version} is stored in db but is not found among available migrations`
|
|
3621
|
-
);
|
|
3622
|
-
}
|
|
3623
|
-
row[1] = name;
|
|
3624
|
-
}
|
|
3625
|
-
await adapter.arrays(`ALTER TABLE ${table} ADD COLUMN name TEXT`);
|
|
3626
|
-
await Promise.all(
|
|
3627
|
-
result.rows.map(
|
|
3628
|
-
([version, name]) => adapter.arrays(`UPDATE ${table} SET name = $2 WHERE version = $1`, [
|
|
3629
|
-
version,
|
|
3630
|
-
name
|
|
3631
|
-
])
|
|
3632
|
-
)
|
|
3633
|
-
);
|
|
3634
|
-
await adapter.arrays(
|
|
3635
|
-
`ALTER TABLE ${table} ALTER COLUMN name SET NOT NULL`
|
|
3636
|
-
);
|
|
3452
|
+
if (inTransaction) {
|
|
3453
|
+
await adapter.query(`RELEASE SAVEPOINT check_migrations_table`);
|
|
3637
3454
|
}
|
|
3638
|
-
let versions = Object.fromEntries(result.rows);
|
|
3639
|
-
if (renameTo) {
|
|
3640
|
-
versions = await renameMigrations(config, adapter, versions, renameTo);
|
|
3641
|
-
}
|
|
3642
|
-
return { map: versions, sequence: result.rows.map((row) => +row[0]) };
|
|
3643
3455
|
} catch (err) {
|
|
3644
3456
|
if (err.code === "42P01") {
|
|
3457
|
+
if (inTransaction) {
|
|
3458
|
+
await adapter.query(`ROLLBACK TO SAVEPOINT check_migrations_table`);
|
|
3459
|
+
}
|
|
3645
3460
|
throw new NoMigrationsTableError();
|
|
3646
3461
|
} else {
|
|
3647
3462
|
throw err;
|
|
3648
3463
|
}
|
|
3649
3464
|
}
|
|
3465
|
+
if (!result.fields[1]) {
|
|
3466
|
+
const { migrations } = await getMigrations(ctx, config, true);
|
|
3467
|
+
const map = {};
|
|
3468
|
+
for (const item of migrations) {
|
|
3469
|
+
const name = path.basename(item.path);
|
|
3470
|
+
map[item.version] = name.slice(getDigitsPrefix(name).length + 1);
|
|
3471
|
+
}
|
|
3472
|
+
for (const row of result.rows) {
|
|
3473
|
+
const [version] = row;
|
|
3474
|
+
const name = map[version];
|
|
3475
|
+
if (!name) {
|
|
3476
|
+
throw new Error(
|
|
3477
|
+
`Migration for version ${version} is stored in db but is not found among available migrations`
|
|
3478
|
+
);
|
|
3479
|
+
}
|
|
3480
|
+
row[1] = name;
|
|
3481
|
+
}
|
|
3482
|
+
await adapter.arrays(`ALTER TABLE ${table} ADD COLUMN name TEXT`);
|
|
3483
|
+
await Promise.all(
|
|
3484
|
+
result.rows.map(
|
|
3485
|
+
([version, name]) => adapter.arrays(`UPDATE ${table} SET name = $2 WHERE version = $1`, [
|
|
3486
|
+
version,
|
|
3487
|
+
name
|
|
3488
|
+
])
|
|
3489
|
+
)
|
|
3490
|
+
);
|
|
3491
|
+
await adapter.arrays(`ALTER TABLE ${table} ALTER COLUMN name SET NOT NULL`);
|
|
3492
|
+
}
|
|
3493
|
+
let versions = Object.fromEntries(result.rows);
|
|
3494
|
+
if (renameTo) {
|
|
3495
|
+
versions = await renameMigrations(config, adapter, versions, renameTo);
|
|
3496
|
+
}
|
|
3497
|
+
return { map: versions, sequence: result.rows.map((row) => +row[0]) };
|
|
3650
3498
|
};
|
|
3651
3499
|
async function renameMigrations(config, trx, versions, renameTo) {
|
|
3652
3500
|
let first;
|
|
@@ -3677,11 +3525,35 @@ async function renameMigrations(config, trx, versions, renameTo) {
|
|
|
3677
3525
|
return updatedVersions;
|
|
3678
3526
|
}
|
|
3679
3527
|
|
|
3528
|
+
const migrateConfigDefaults = {
|
|
3529
|
+
migrationId: { serial: 4 },
|
|
3530
|
+
migrationsTable: "schemaMigrations",
|
|
3531
|
+
transaction: "single"
|
|
3532
|
+
};
|
|
3533
|
+
const handleConfigLogger = (config) => {
|
|
3534
|
+
return config.log === true ? config.logger || console : config.log === false ? void 0 : config.logger;
|
|
3535
|
+
};
|
|
3536
|
+
const processMigrateConfig = (config) => {
|
|
3537
|
+
let migrationsPath;
|
|
3538
|
+
if (!("migrations" in config)) {
|
|
3539
|
+
migrationsPath = config.migrationsPath ? config.migrationsPath : path$1.join("src", "db", "migrations");
|
|
3540
|
+
if (config.basePath && !path$1.isAbsolute(migrationsPath)) {
|
|
3541
|
+
migrationsPath = path$1.resolve(config.basePath, migrationsPath);
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
return {
|
|
3545
|
+
...migrateConfigDefaults,
|
|
3546
|
+
...config,
|
|
3547
|
+
migrationsPath,
|
|
3548
|
+
logger: handleConfigLogger(config)
|
|
3549
|
+
};
|
|
3550
|
+
};
|
|
3680
3551
|
const transactionIfSingle = (adapter, config, fn) => {
|
|
3681
3552
|
return config.transaction === "single" ? transaction(adapter, config, fn) : fn(adapter);
|
|
3682
3553
|
};
|
|
3683
3554
|
function makeMigrateFn(up, defaultCount, fn) {
|
|
3684
|
-
return async (db,
|
|
3555
|
+
return async (db, publicConfig, params) => {
|
|
3556
|
+
const config = processMigrateConfig(publicConfig);
|
|
3685
3557
|
const ctx = params?.ctx || {};
|
|
3686
3558
|
const set = await getMigrations(ctx, config, up);
|
|
3687
3559
|
const count = params?.count ?? defaultCount;
|
|
@@ -3724,7 +3596,16 @@ function makeMigrateFn(up, defaultCount, fn) {
|
|
|
3724
3596
|
const migrate = makeMigrateFn(
|
|
3725
3597
|
true,
|
|
3726
3598
|
Infinity,
|
|
3727
|
-
(trx, config, set, versions, count, force) => migrateOrRollback(
|
|
3599
|
+
(trx, config, set, versions, count, force) => migrateOrRollback(
|
|
3600
|
+
trx,
|
|
3601
|
+
config,
|
|
3602
|
+
set,
|
|
3603
|
+
versions,
|
|
3604
|
+
count,
|
|
3605
|
+
true,
|
|
3606
|
+
false,
|
|
3607
|
+
force
|
|
3608
|
+
)
|
|
3728
3609
|
);
|
|
3729
3610
|
const migrateAndClose = async (db, config, params) => {
|
|
3730
3611
|
const adapter = getMaybeTransactionAdapter(db);
|
|
@@ -3732,26 +3613,46 @@ const migrateAndClose = async (db, config, params) => {
|
|
|
3732
3613
|
await adapter.close();
|
|
3733
3614
|
};
|
|
3734
3615
|
async function runMigration(db, ...args) {
|
|
3735
|
-
const [
|
|
3616
|
+
const [rawConfig, migration] = args.length === 1 ? [{}, args[0]] : [args[0], args[1]];
|
|
3617
|
+
const config = {
|
|
3618
|
+
...rawConfig,
|
|
3619
|
+
logger: handleConfigLogger(rawConfig)
|
|
3620
|
+
};
|
|
3736
3621
|
const adapter = getMaybeTransactionAdapter(db);
|
|
3737
3622
|
await transaction(adapter, config, async (trx) => {
|
|
3738
3623
|
clearChanges();
|
|
3739
3624
|
const changes = await getChanges({ load: migration });
|
|
3740
|
-
|
|
3741
|
-
await applyMigration(trx, true, changes, config2);
|
|
3625
|
+
await applyMigration(trx, true, changes, config);
|
|
3742
3626
|
});
|
|
3743
3627
|
}
|
|
3744
3628
|
const rollback = makeMigrateFn(
|
|
3745
3629
|
false,
|
|
3746
3630
|
1,
|
|
3747
|
-
(trx, config, set, versions, count, force) => migrateOrRollback(
|
|
3631
|
+
(trx, config, set, versions, count, force) => migrateOrRollback(
|
|
3632
|
+
trx,
|
|
3633
|
+
config,
|
|
3634
|
+
set,
|
|
3635
|
+
versions,
|
|
3636
|
+
count,
|
|
3637
|
+
false,
|
|
3638
|
+
false,
|
|
3639
|
+
force
|
|
3640
|
+
)
|
|
3748
3641
|
);
|
|
3749
3642
|
const redo = makeMigrateFn(
|
|
3750
3643
|
true,
|
|
3751
3644
|
1,
|
|
3752
3645
|
async (trx, config, set, versions, count, force) => {
|
|
3753
3646
|
set.migrations.reverse();
|
|
3754
|
-
await migrateOrRollback(
|
|
3647
|
+
await migrateOrRollback(
|
|
3648
|
+
trx,
|
|
3649
|
+
config,
|
|
3650
|
+
set,
|
|
3651
|
+
versions,
|
|
3652
|
+
count,
|
|
3653
|
+
false,
|
|
3654
|
+
true
|
|
3655
|
+
);
|
|
3755
3656
|
set.migrations.reverse();
|
|
3756
3657
|
return migrateOrRollback(
|
|
3757
3658
|
trx,
|
|
@@ -3822,7 +3723,7 @@ const migrateOrRollback = async (trx, config, set, versions, count, up, redo2, f
|
|
|
3822
3723
|
await changeMigratedVersion(adapter, up, file, config);
|
|
3823
3724
|
(migrations ?? (migrations = [])).push(file);
|
|
3824
3725
|
if (up) {
|
|
3825
|
-
const name = path.basename(file.path);
|
|
3726
|
+
const name = path$1.basename(file.path);
|
|
3826
3727
|
versionsMap[file.version] = name;
|
|
3827
3728
|
sequence.push(+file.version);
|
|
3828
3729
|
} else {
|
|
@@ -3869,7 +3770,7 @@ const checkMigrationOrder = (config, set, { sequence, map }, force) => {
|
|
|
3869
3770
|
if (version > last || map[file.version]) continue;
|
|
3870
3771
|
if (!force) {
|
|
3871
3772
|
throw new Error(
|
|
3872
|
-
`Cannot migrate ${path.basename(
|
|
3773
|
+
`Cannot migrate ${path$1.basename(
|
|
3873
3774
|
file.path
|
|
3874
3775
|
)} because the higher position ${map[versionToString(config, last)]} was already migrated.
|
|
3875
3776
|
Run \`**db command** up force\` to rollback the above migrations and migrate all`
|
|
@@ -3905,151 +3806,342 @@ const runMigrationInOwnTransaction = (adapter, up, changes, config) => {
|
|
|
3905
3806
|
);
|
|
3906
3807
|
};
|
|
3907
3808
|
const applyMigration = async (trx, up, changes, config) => {
|
|
3908
|
-
const
|
|
3809
|
+
const { adapter, getDb: getDb2 } = createMigrationInterface(trx, up, config);
|
|
3909
3810
|
if (changes.length) {
|
|
3910
3811
|
const from = up ? 0 : changes.length - 1;
|
|
3911
3812
|
const to = up ? changes.length : -1;
|
|
3912
3813
|
const step = up ? 1 : -1;
|
|
3913
3814
|
for (let i = from; i !== to; i += step) {
|
|
3914
|
-
|
|
3815
|
+
const change = changes[i];
|
|
3816
|
+
const db = getDb2(change.config.columnTypes);
|
|
3817
|
+
await change.fn(db, up);
|
|
3915
3818
|
}
|
|
3916
3819
|
}
|
|
3917
|
-
return
|
|
3820
|
+
return adapter;
|
|
3918
3821
|
};
|
|
3919
3822
|
const changeMigratedVersion = async (adapter, up, file, config) => {
|
|
3920
3823
|
await (up ? saveMigratedVersion : deleteMigratedVersion)(
|
|
3921
3824
|
adapter,
|
|
3922
3825
|
file.version,
|
|
3923
|
-
path.basename(file.path).slice(file.version.length + 1),
|
|
3826
|
+
path$1.basename(file.path).slice(file.version.length + 1),
|
|
3924
3827
|
config
|
|
3925
3828
|
);
|
|
3926
3829
|
};
|
|
3927
3830
|
|
|
3928
|
-
const
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
})
|
|
3939
|
-
);
|
|
3940
|
-
});
|
|
3941
|
-
if (files > 0) {
|
|
3942
|
-
config.logger?.log(
|
|
3943
|
-
`Applied ${files} recurrent migration file${files > 1 ? "s" : ""}`
|
|
3831
|
+
const rakeDbConfigDefaults = {
|
|
3832
|
+
...migrateConfigDefaults,
|
|
3833
|
+
schemaConfig: defaultSchemaConfig,
|
|
3834
|
+
snakeCase: false,
|
|
3835
|
+
commands: {},
|
|
3836
|
+
log: true,
|
|
3837
|
+
logger: console,
|
|
3838
|
+
import() {
|
|
3839
|
+
throw new Error(
|
|
3840
|
+
"Add `import: (path) => import(path),` setting to `rakeDb` config"
|
|
3944
3841
|
);
|
|
3945
3842
|
}
|
|
3946
3843
|
};
|
|
3947
|
-
const readdirRecursive = async (dirPath, cb) => {
|
|
3948
|
-
const list = await readdir(dirPath).catch((err) => {
|
|
3949
|
-
if (err.code !== "ENOENT") throw err;
|
|
3950
|
-
return;
|
|
3951
|
-
});
|
|
3952
|
-
if (!list) return;
|
|
3953
|
-
await Promise.all(
|
|
3954
|
-
list.map(async (item) => {
|
|
3955
|
-
const path = join(dirPath, item);
|
|
3956
|
-
const info = await stat(path);
|
|
3957
|
-
if (info.isDirectory()) {
|
|
3958
|
-
await readdirRecursive(path, cb);
|
|
3959
|
-
} else if (info.isFile() && path.endsWith(".sql")) {
|
|
3960
|
-
await cb(path);
|
|
3961
|
-
}
|
|
3962
|
-
})
|
|
3963
|
-
);
|
|
3964
|
-
};
|
|
3965
3844
|
|
|
3966
|
-
const
|
|
3967
|
-
const
|
|
3968
|
-
const
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
}
|
|
3986
|
-
);
|
|
3987
|
-
if (!res) continue;
|
|
3988
|
-
if (action === "create") {
|
|
3989
|
-
await adapter.transaction(async (tx) => {
|
|
3990
|
-
const schema = tx.getSchema();
|
|
3991
|
-
if (schema) {
|
|
3992
|
-
const quoted = `"${typeof schema === "function" ? schema() : schema}"`;
|
|
3993
|
-
const res2 = await createSchema$1(tx, quoted);
|
|
3994
|
-
if (res2 === "done") {
|
|
3995
|
-
config.logger?.log(`Created schema ${quoted}`);
|
|
3996
|
-
}
|
|
3997
|
-
}
|
|
3998
|
-
await createMigrationsSchemaAndTable(tx, config);
|
|
3999
|
-
});
|
|
4000
|
-
if (!dontClose) {
|
|
4001
|
-
await adapter.close();
|
|
4002
|
-
}
|
|
4003
|
-
}
|
|
4004
|
-
}
|
|
4005
|
-
};
|
|
4006
|
-
const resetDatabaseCommand = async (adapters, config) => {
|
|
4007
|
-
await createOrDropDatabase("drop", adapters, config);
|
|
4008
|
-
await createOrDropDatabase("create", adapters, config, true);
|
|
4009
|
-
for (const adapter of adapters) {
|
|
4010
|
-
await migrate(adapter, config);
|
|
4011
|
-
}
|
|
4012
|
-
if (config.recurrentPath) {
|
|
4013
|
-
await runRecurrentMigrations(adapters, config);
|
|
4014
|
-
}
|
|
4015
|
-
await Promise.all(adapters.map((adapter) => adapter.close()));
|
|
4016
|
-
};
|
|
4017
|
-
const run = async (adapter, config, params) => {
|
|
4018
|
-
try {
|
|
4019
|
-
const res = await params.command(adapter);
|
|
4020
|
-
config.logger?.log(
|
|
4021
|
-
res === "done" ? params.doneMessage() : params.alreadyMessage()
|
|
4022
|
-
);
|
|
4023
|
-
await adapter.close();
|
|
4024
|
-
return true;
|
|
4025
|
-
} catch (err) {
|
|
4026
|
-
if (err instanceof CreateOrDropError) {
|
|
4027
|
-
if (err.status === "ssl-required") {
|
|
4028
|
-
config.logger?.log(
|
|
4029
|
-
"SSL is required: append ?ssl=true to the database url string"
|
|
4030
|
-
);
|
|
4031
|
-
return false;
|
|
4032
|
-
}
|
|
4033
|
-
if (err.status === "forbidden" || err.status === "auth-failed") {
|
|
4034
|
-
let message = params.deniedMessage();
|
|
4035
|
-
const host = adapter.getHost();
|
|
4036
|
-
const isLocal = host === "localhost";
|
|
4037
|
-
if (!isLocal) {
|
|
4038
|
-
message += `
|
|
4039
|
-
Don't use this command for database service providers, only for a local db.`;
|
|
4040
|
-
}
|
|
4041
|
-
config.logger?.log(message);
|
|
4042
|
-
const creds = await params.askAdminCreds();
|
|
4043
|
-
if (!creds) return false;
|
|
4044
|
-
return run(adapter.reconfigure(creds), config, params);
|
|
4045
|
-
}
|
|
3845
|
+
const ESC = "\x1B";
|
|
3846
|
+
const CSI = `${ESC}[`;
|
|
3847
|
+
const cursorShow = `${CSI}?25h`;
|
|
3848
|
+
const cursorHide = `${CSI}?25l`;
|
|
3849
|
+
const { stdin, stdout } = process;
|
|
3850
|
+
const visibleChars = (s) => s.replace(
|
|
3851
|
+
// eslint-disable-next-line no-control-regex
|
|
3852
|
+
/[\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,
|
|
3853
|
+
""
|
|
3854
|
+
).length;
|
|
3855
|
+
const clear = (text) => {
|
|
3856
|
+
const rows = text.split(/\r?\n/).reduce(
|
|
3857
|
+
(rows2, line) => rows2 + 1 + Math.floor(Math.max(visibleChars(line) - 1, 0) / stdout.columns),
|
|
3858
|
+
0
|
|
3859
|
+
);
|
|
3860
|
+
let clear2 = "";
|
|
3861
|
+
for (let i = 0; i < rows; i++) {
|
|
3862
|
+
clear2 += `${CSI}2K`;
|
|
3863
|
+
if (i < rows - 1) {
|
|
3864
|
+
clear2 += `${CSI}${i < rows - 1 ? "1A" : "G"}`;
|
|
4046
3865
|
}
|
|
4047
|
-
throw err;
|
|
4048
3866
|
}
|
|
3867
|
+
return clear2;
|
|
4049
3868
|
};
|
|
4050
|
-
const
|
|
4051
|
-
|
|
4052
|
-
|
|
3869
|
+
const prompt = async ({
|
|
3870
|
+
render,
|
|
3871
|
+
onKeyPress,
|
|
3872
|
+
validate,
|
|
3873
|
+
value,
|
|
3874
|
+
cursor: showCursor
|
|
3875
|
+
}) => {
|
|
3876
|
+
stdin.resume();
|
|
3877
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
3878
|
+
stdin.setEncoding("utf-8");
|
|
3879
|
+
if (!showCursor) stdout.write(cursorHide);
|
|
3880
|
+
return new Promise((res) => {
|
|
3881
|
+
let prevText;
|
|
3882
|
+
const ctx = {
|
|
3883
|
+
value,
|
|
3884
|
+
submitted: false,
|
|
3885
|
+
render() {
|
|
3886
|
+
let text = (ctx.submitted ? colors.greenBold("\u2714") : colors.yellowBold("?")) + " " + render(ctx);
|
|
3887
|
+
if (ctx.submitted) text += "\n";
|
|
3888
|
+
stdout.write(prevText ? clear(prevText) + "\r" + text : text);
|
|
3889
|
+
prevText = text;
|
|
3890
|
+
},
|
|
3891
|
+
submit(value2) {
|
|
3892
|
+
if (value2 !== void 0) ctx.value = value2;
|
|
3893
|
+
if (ctx.value === void 0 || validate && !validate?.(ctx)) return;
|
|
3894
|
+
ctx.submitted = true;
|
|
3895
|
+
ctx.render();
|
|
3896
|
+
close();
|
|
3897
|
+
res(ctx.value);
|
|
3898
|
+
}
|
|
3899
|
+
};
|
|
3900
|
+
const close = () => {
|
|
3901
|
+
if (!showCursor) stdout.write(cursorShow);
|
|
3902
|
+
if (stdin.isTTY) stdin.setRawMode(false);
|
|
3903
|
+
stdin.off("data", keypress);
|
|
3904
|
+
stdin.pause();
|
|
3905
|
+
};
|
|
3906
|
+
const keypress = (s) => {
|
|
3907
|
+
if (s === "" || s === "") {
|
|
3908
|
+
close?.();
|
|
3909
|
+
process.exit(0);
|
|
3910
|
+
}
|
|
3911
|
+
if (s === "\r" || s === "\n" || s === "\r\n") {
|
|
3912
|
+
ctx.submit();
|
|
3913
|
+
} else {
|
|
3914
|
+
onKeyPress(ctx, s);
|
|
3915
|
+
}
|
|
3916
|
+
};
|
|
3917
|
+
stdin.on("data", keypress);
|
|
3918
|
+
ctx.render();
|
|
3919
|
+
});
|
|
3920
|
+
};
|
|
3921
|
+
const defaultActive = (s) => `${colors.blueBold("\u276F")} ${s}`;
|
|
3922
|
+
const defaultInactive = (s) => ` ${s}`;
|
|
3923
|
+
const promptSelect = ({
|
|
3924
|
+
message,
|
|
3925
|
+
options,
|
|
3926
|
+
active = defaultActive,
|
|
3927
|
+
inactive = defaultInactive
|
|
3928
|
+
}) => prompt({
|
|
3929
|
+
value: 0,
|
|
3930
|
+
render(ctx) {
|
|
3931
|
+
let text = `${message} ${colors.pale(
|
|
3932
|
+
"Use arrows or jk. Press enter to submit."
|
|
3933
|
+
)}
|
|
3934
|
+
`;
|
|
3935
|
+
for (let i = 0; i < options.length; i++) {
|
|
3936
|
+
text += (ctx.value === i ? active : inactive)(options[i]) + "\n";
|
|
3937
|
+
}
|
|
3938
|
+
return text;
|
|
3939
|
+
},
|
|
3940
|
+
onKeyPress(ctx, s) {
|
|
3941
|
+
ctx.value = s === "\x1B[H" ? 0 : s === "\x1B[F" ? options.length - 1 : s === "\x1B[A" || s === "k" ? ctx.value === 0 ? options.length - 1 : ctx.value - 1 : s === "\x1B[B" || s === "j" || s === " " ? ctx.value === options.length - 1 ? 0 : ctx.value + 1 : ctx.value;
|
|
3942
|
+
ctx.render();
|
|
3943
|
+
}
|
|
3944
|
+
});
|
|
3945
|
+
const promptConfirm = ({
|
|
3946
|
+
message
|
|
3947
|
+
}) => prompt({
|
|
3948
|
+
value: true,
|
|
3949
|
+
render(ctx) {
|
|
3950
|
+
return `${colors.bright(message)}
|
|
3951
|
+
${ctx.submitted ? `> ${ctx.value ? colors.greenBold("Yes") : colors.yellowBold("No")}` : colors.pale(`> (Y/n)`)}
|
|
3952
|
+
`;
|
|
3953
|
+
},
|
|
3954
|
+
onKeyPress(ctx, s) {
|
|
3955
|
+
let ok;
|
|
3956
|
+
if (s === "y" || s === "Y") ok = true;
|
|
3957
|
+
else if (s === "n" || s === "N") ok = false;
|
|
3958
|
+
if (ok !== void 0) {
|
|
3959
|
+
ctx.submit(ok);
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
});
|
|
3963
|
+
const promptText = ({
|
|
3964
|
+
message,
|
|
3965
|
+
default: def = "",
|
|
3966
|
+
password,
|
|
3967
|
+
min
|
|
3968
|
+
}) => {
|
|
3969
|
+
let showDefault = true;
|
|
3970
|
+
let x = 0;
|
|
3971
|
+
const renderValue = (ctx) => password ? "*".repeat(ctx.value.length) : ctx.value;
|
|
3972
|
+
return prompt({
|
|
3973
|
+
value: def,
|
|
3974
|
+
cursor: true,
|
|
3975
|
+
validate: (ctx) => !min || ctx.value.length >= min,
|
|
3976
|
+
render(ctx) {
|
|
3977
|
+
let text = `${colors.bright(message)}
|
|
3978
|
+
> ${ctx.submitted ? renderValue(ctx) : showDefault ? colors.pale(def) + "\b".repeat(def.length) : ctx.value}`;
|
|
3979
|
+
if (ctx.submitted) text += "\n";
|
|
3980
|
+
return text;
|
|
3981
|
+
},
|
|
3982
|
+
onKeyPress(ctx, s) {
|
|
3983
|
+
let value = showDefault ? "" : ctx.value;
|
|
3984
|
+
if (s === "\x1B[D" && x > 0) {
|
|
3985
|
+
x--;
|
|
3986
|
+
stdout.write("\b");
|
|
3987
|
+
} else if (s === "\x1B[C" && x < value.length) {
|
|
3988
|
+
stdout.write(value[x]);
|
|
3989
|
+
x++;
|
|
3990
|
+
}
|
|
3991
|
+
if (s !== "\x7F" && s !== "\x1B[3~" && !visibleChars(s)) return;
|
|
3992
|
+
if (showDefault) {
|
|
3993
|
+
showDefault = false;
|
|
3994
|
+
stdout.write(" ".repeat(def.length) + "\b".repeat(def.length));
|
|
3995
|
+
}
|
|
3996
|
+
const prev = value;
|
|
3997
|
+
const prevX = x;
|
|
3998
|
+
if (s === "\x7F") {
|
|
3999
|
+
if (x > 0) {
|
|
4000
|
+
value = value.slice(0, x - 1) + value.slice(x);
|
|
4001
|
+
x--;
|
|
4002
|
+
}
|
|
4003
|
+
} else if (s === "\x1B[3~") {
|
|
4004
|
+
if (x < value.length) {
|
|
4005
|
+
value = value.slice(0, x) + value.slice(x + 1);
|
|
4006
|
+
}
|
|
4007
|
+
} else {
|
|
4008
|
+
value = value.slice(0, x) + s + value.slice(x);
|
|
4009
|
+
x++;
|
|
4010
|
+
}
|
|
4011
|
+
ctx.value = value;
|
|
4012
|
+
const spaces = prev.length - value.length;
|
|
4013
|
+
stdout.write(
|
|
4014
|
+
"\b".repeat(prevX) + renderValue(ctx) + (spaces > 0 ? " ".repeat(spaces) + "\b".repeat(spaces) : "") + "\b".repeat(value.length - x)
|
|
4015
|
+
);
|
|
4016
|
+
}
|
|
4017
|
+
});
|
|
4018
|
+
};
|
|
4019
|
+
|
|
4020
|
+
const runRecurrentMigrations = async (adapters, config) => {
|
|
4021
|
+
let dbs;
|
|
4022
|
+
let files = 0;
|
|
4023
|
+
await readdirRecursive(config.recurrentPath, async (path) => {
|
|
4024
|
+
files++;
|
|
4025
|
+
dbs ?? (dbs = adapters.map((adapter) => createDbWithAdapter({ adapter })));
|
|
4026
|
+
const sql = await readFile(path, "utf-8");
|
|
4027
|
+
await Promise.all(
|
|
4028
|
+
dbs.map(async (db) => {
|
|
4029
|
+
await db.adapter.arrays(sql);
|
|
4030
|
+
})
|
|
4031
|
+
);
|
|
4032
|
+
});
|
|
4033
|
+
if (files > 0) {
|
|
4034
|
+
config.logger?.log(
|
|
4035
|
+
`Applied ${files} recurrent migration file${files > 1 ? "s" : ""}`
|
|
4036
|
+
);
|
|
4037
|
+
}
|
|
4038
|
+
};
|
|
4039
|
+
const readdirRecursive = async (dirPath, cb) => {
|
|
4040
|
+
const list = await readdir(dirPath).catch((err) => {
|
|
4041
|
+
if (err.code !== "ENOENT") throw err;
|
|
4042
|
+
return;
|
|
4043
|
+
});
|
|
4044
|
+
if (!list) return;
|
|
4045
|
+
await Promise.all(
|
|
4046
|
+
list.map(async (item) => {
|
|
4047
|
+
const path = join(dirPath, item);
|
|
4048
|
+
const info = await stat(path);
|
|
4049
|
+
if (info.isDirectory()) {
|
|
4050
|
+
await readdirRecursive(path, cb);
|
|
4051
|
+
} else if (info.isFile() && path.endsWith(".sql")) {
|
|
4052
|
+
await cb(path);
|
|
4053
|
+
}
|
|
4054
|
+
})
|
|
4055
|
+
);
|
|
4056
|
+
};
|
|
4057
|
+
|
|
4058
|
+
const createDatabaseCommand = (adapters, config, dontClose) => createOrDropDatabase("create", adapters, config, dontClose);
|
|
4059
|
+
const dropDatabaseCommand = (adapters, config) => createOrDropDatabase("drop", adapters, config);
|
|
4060
|
+
const createOrDropDatabase = async (action, adapters, config, dontClose) => {
|
|
4061
|
+
const fn = action === "create" ? createDatabase : dropDatabase;
|
|
4062
|
+
for (const adapter of adapters) {
|
|
4063
|
+
const database = adapter.getDatabase();
|
|
4064
|
+
const owner = adapter.getUser();
|
|
4065
|
+
const res = await run(
|
|
4066
|
+
adapter.reconfigure({ database: "postgres" }),
|
|
4067
|
+
config,
|
|
4068
|
+
{
|
|
4069
|
+
command: (adapter2) => fn(adapter2, {
|
|
4070
|
+
database,
|
|
4071
|
+
owner
|
|
4072
|
+
}),
|
|
4073
|
+
doneMessage: () => `Database ${database} successfully ${action === "create" ? "created" : "dropped"}`,
|
|
4074
|
+
alreadyMessage: () => `Database ${database} ${action === "create" ? "already exists" : "does not exist"}`,
|
|
4075
|
+
deniedMessage: () => `Permission denied to ${action} database.`,
|
|
4076
|
+
askAdminCreds: () => askForAdminCredentials(action === "create")
|
|
4077
|
+
}
|
|
4078
|
+
);
|
|
4079
|
+
if (!res) continue;
|
|
4080
|
+
if (action === "create") {
|
|
4081
|
+
await adapter.transaction(async (tx) => {
|
|
4082
|
+
const schema = tx.getSchema();
|
|
4083
|
+
if (schema) {
|
|
4084
|
+
const quoted = `"${typeof schema === "function" ? schema() : schema}"`;
|
|
4085
|
+
const res2 = await createSchema(tx, quoted);
|
|
4086
|
+
if (res2 === "done") {
|
|
4087
|
+
config.logger?.log(`Created schema ${quoted}`);
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
await createMigrationsSchemaAndTable(tx, config);
|
|
4091
|
+
});
|
|
4092
|
+
if (!dontClose) {
|
|
4093
|
+
await adapter.close();
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
};
|
|
4098
|
+
const resetDatabaseCommand = async (adapters, config) => {
|
|
4099
|
+
await createOrDropDatabase("drop", adapters, config);
|
|
4100
|
+
await createOrDropDatabase("create", adapters, config, true);
|
|
4101
|
+
for (const adapter of adapters) {
|
|
4102
|
+
await migrate(adapter, config);
|
|
4103
|
+
}
|
|
4104
|
+
if (config.recurrentPath) {
|
|
4105
|
+
await runRecurrentMigrations(adapters, config);
|
|
4106
|
+
}
|
|
4107
|
+
await Promise.all(adapters.map((adapter) => adapter.close()));
|
|
4108
|
+
};
|
|
4109
|
+
const run = async (adapter, config, params) => {
|
|
4110
|
+
try {
|
|
4111
|
+
const res = await params.command(adapter);
|
|
4112
|
+
config.logger?.log(
|
|
4113
|
+
res === "done" ? params.doneMessage() : params.alreadyMessage()
|
|
4114
|
+
);
|
|
4115
|
+
await adapter.close();
|
|
4116
|
+
return true;
|
|
4117
|
+
} catch (err) {
|
|
4118
|
+
if (err instanceof CreateOrDropError) {
|
|
4119
|
+
if (err.status === "ssl-required") {
|
|
4120
|
+
config.logger?.log(
|
|
4121
|
+
"SSL is required: append ?ssl=true to the database url string"
|
|
4122
|
+
);
|
|
4123
|
+
return false;
|
|
4124
|
+
}
|
|
4125
|
+
if (err.status === "forbidden" || err.status === "auth-failed") {
|
|
4126
|
+
let message = params.deniedMessage();
|
|
4127
|
+
const host = adapter.getHost();
|
|
4128
|
+
const isLocal = host === "localhost";
|
|
4129
|
+
if (!isLocal) {
|
|
4130
|
+
message += `
|
|
4131
|
+
Don't use this command for database service providers, only for a local db.`;
|
|
4132
|
+
}
|
|
4133
|
+
config.logger?.log(message);
|
|
4134
|
+
const creds = await params.askAdminCreds();
|
|
4135
|
+
if (!creds) return false;
|
|
4136
|
+
return run(adapter.reconfigure(creds), config, params);
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
throw err;
|
|
4140
|
+
}
|
|
4141
|
+
};
|
|
4142
|
+
const askForAdminCredentials = async (create) => {
|
|
4143
|
+
const ok = await promptConfirm({
|
|
4144
|
+
message: `Would you like to share admin credentials to ${create ? "create" : "drop"} a database?`
|
|
4053
4145
|
});
|
|
4054
4146
|
if (!ok) {
|
|
4055
4147
|
return;
|
|
@@ -6004,195 +6096,83 @@ const dbConstraintToTableConstraint = (ctx, table, item) => {
|
|
|
6004
6096
|
references: references ? {
|
|
6005
6097
|
columns: references.columns,
|
|
6006
6098
|
fnOrTable: getReferencesTable(ctx, references),
|
|
6007
|
-
foreignColumns: references.foreignColumns,
|
|
6008
|
-
options: {
|
|
6009
|
-
match: matchMap[references.match],
|
|
6010
|
-
onUpdate: fkeyActionMap[references.onUpdate],
|
|
6011
|
-
onDelete: fkeyActionMap[references.onDelete]
|
|
6012
|
-
}
|
|
6013
|
-
} : void 0,
|
|
6014
|
-
check: check ? raw({ raw: check.expression }) : void 0
|
|
6015
|
-
};
|
|
6016
|
-
const name = item.name && item.name !== getConstraintName(table.name, constraint, ctx.snakeCase) ? item.name : void 0;
|
|
6017
|
-
if (name) {
|
|
6018
|
-
constraint.name = name;
|
|
6019
|
-
if (constraint.references?.options) {
|
|
6020
|
-
constraint.references.options.name = name;
|
|
6021
|
-
}
|
|
6022
|
-
}
|
|
6023
|
-
return constraint;
|
|
6024
|
-
};
|
|
6025
|
-
const makeIndexOrExcludeOptions = (tableName, index, key) => {
|
|
6026
|
-
return {
|
|
6027
|
-
name: index.name !== (key === "indexes" ? getIndexName : getExcludeName)(
|
|
6028
|
-
tableName,
|
|
6029
|
-
index.columns
|
|
6030
|
-
) ? index.name : void 0,
|
|
6031
|
-
using: index.using === "btree" ? void 0 : index.using,
|
|
6032
|
-
unique: index.unique || void 0,
|
|
6033
|
-
include: index.include,
|
|
6034
|
-
nullsNotDistinct: index.nullsNotDistinct || void 0,
|
|
6035
|
-
with: index.with,
|
|
6036
|
-
tablespace: index.tablespace,
|
|
6037
|
-
where: index.where
|
|
6038
|
-
};
|
|
6039
|
-
};
|
|
6040
|
-
const checkIfIsOuterRecursiveFkey = (data, table, references) => {
|
|
6041
|
-
const referencesId = `${references.foreignSchema}.${references.foreignTable}`;
|
|
6042
|
-
const tableId = `${table.schemaName}.${table.name}`;
|
|
6043
|
-
for (const other of data.tables) {
|
|
6044
|
-
const id = `${other.schemaName}.${other.name}`;
|
|
6045
|
-
if (referencesId === id) {
|
|
6046
|
-
for (const c of data.constraints) {
|
|
6047
|
-
if (c.tableName === other.name && c.schemaName === other.schemaName && c.references?.foreignTable === table.name && c.references.foreignSchema === table.schemaName && tableId < id) {
|
|
6048
|
-
return true;
|
|
6049
|
-
}
|
|
6050
|
-
}
|
|
6051
|
-
break;
|
|
6052
|
-
}
|
|
6053
|
-
}
|
|
6054
|
-
return false;
|
|
6055
|
-
};
|
|
6056
|
-
|
|
6057
|
-
const pullDbStructure = async (adapter, config) => {
|
|
6058
|
-
const currentSchema = adapter.searchPath || "public";
|
|
6059
|
-
const ctx = makeStructureToAstCtx(config, currentSchema);
|
|
6060
|
-
const ast = await structureToAst(ctx, adapter, config);
|
|
6061
|
-
const result = astToMigration(currentSchema, config, ast);
|
|
6062
|
-
if (!result) return;
|
|
6063
|
-
const version = await makeFileVersion({}, config);
|
|
6064
|
-
await writeMigrationFile(config, version, "pull", result);
|
|
6065
|
-
const silentQueries = Object.assign(adapter, {
|
|
6066
|
-
silentQuery: adapter.query,
|
|
6067
|
-
silentArrays: adapter.arrays
|
|
6068
|
-
});
|
|
6069
|
-
await saveMigratedVersion(silentQueries, version, "pull", config);
|
|
6070
|
-
const unsupportedEntries = Object.entries(ctx.unsupportedTypes);
|
|
6071
|
-
const len = unsupportedEntries.length;
|
|
6072
|
-
if (len) {
|
|
6073
|
-
let count = 0;
|
|
6074
|
-
config.logger?.warn(
|
|
6075
|
-
`Found unsupported types:
|
|
6076
|
-
${unsupportedEntries.map(([type, columns]) => {
|
|
6077
|
-
count += columns.length;
|
|
6078
|
-
return `- ${type} is used for column${columns.length > 1 ? "s" : ""} ${columns.join(", ")}`;
|
|
6079
|
-
}).join("\n")}
|
|
6080
|
-
Append \`as\` method manually to ${count > 1 ? "these" : "this"} column${count > 1 ? "s" : ""} to treat ${count > 1 ? "them" : "it"} as other column type`
|
|
6081
|
-
);
|
|
6082
|
-
}
|
|
6083
|
-
config.logger?.log("Database pulled successfully");
|
|
6084
|
-
};
|
|
6085
|
-
|
|
6086
|
-
const migrationConfigDefaults = {
|
|
6087
|
-
schemaConfig: defaultSchemaConfig,
|
|
6088
|
-
migrationsPath: path.join("src", "db", "migrations"),
|
|
6089
|
-
migrationId: { serial: 4 },
|
|
6090
|
-
migrationsTable: "schemaMigrations",
|
|
6091
|
-
snakeCase: false,
|
|
6092
|
-
commands: {},
|
|
6093
|
-
log: true,
|
|
6094
|
-
logger: console,
|
|
6095
|
-
import() {
|
|
6096
|
-
throw new Error(
|
|
6097
|
-
"Add `import: (path) => import(path),` setting to `rakeDb` config"
|
|
6098
|
-
);
|
|
6099
|
-
}
|
|
6100
|
-
};
|
|
6101
|
-
const ensureMigrationsPath = (config) => {
|
|
6102
|
-
if (!config.migrationsPath) {
|
|
6103
|
-
config.migrationsPath = migrationConfigDefaults.migrationsPath;
|
|
6104
|
-
}
|
|
6105
|
-
if (!path.isAbsolute(config.migrationsPath)) {
|
|
6106
|
-
config.migrationsPath = path.resolve(
|
|
6107
|
-
config.basePath,
|
|
6108
|
-
config.migrationsPath
|
|
6109
|
-
);
|
|
6110
|
-
}
|
|
6111
|
-
return config;
|
|
6112
|
-
};
|
|
6113
|
-
const ensureBasePathAndDbScript = (config, intermediateCallers2 = 0) => {
|
|
6114
|
-
if (config.basePath && config.dbScript) return config;
|
|
6115
|
-
let filePath = getStackTrace()?.[3 + intermediateCallers2]?.getFileName();
|
|
6116
|
-
if (!filePath) {
|
|
6117
|
-
throw new Error(
|
|
6118
|
-
"Failed to determine path to db script. Please set basePath option of rakeDb"
|
|
6119
|
-
);
|
|
6120
|
-
}
|
|
6121
|
-
if (filePath.startsWith("file://")) {
|
|
6122
|
-
filePath = fileURLToPath(filePath);
|
|
6123
|
-
}
|
|
6124
|
-
const ext = path.extname(filePath);
|
|
6125
|
-
if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
|
|
6126
|
-
throw new Error(
|
|
6127
|
-
`Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
|
|
6128
|
-
);
|
|
6129
|
-
}
|
|
6130
|
-
config.basePath = path.dirname(filePath);
|
|
6131
|
-
config.dbScript = path.basename(filePath);
|
|
6132
|
-
return config;
|
|
6133
|
-
};
|
|
6134
|
-
let intermediateCallers = 0;
|
|
6135
|
-
const incrementIntermediateCaller = () => {
|
|
6136
|
-
intermediateCallers++;
|
|
6137
|
-
};
|
|
6138
|
-
const makeRakeDbConfig = (config, args) => {
|
|
6139
|
-
const ic = intermediateCallers;
|
|
6140
|
-
intermediateCallers = 0;
|
|
6141
|
-
const result = {
|
|
6142
|
-
...migrationConfigDefaults,
|
|
6143
|
-
...config,
|
|
6144
|
-
__rakeDbConfig: true
|
|
6145
|
-
};
|
|
6146
|
-
if (!result.log) {
|
|
6147
|
-
delete result.logger;
|
|
6148
|
-
}
|
|
6149
|
-
ensureBasePathAndDbScript(result, ic);
|
|
6150
|
-
ensureMigrationsPath(result);
|
|
6151
|
-
if (!result.recurrentPath) {
|
|
6152
|
-
result.recurrentPath = path.join(
|
|
6153
|
-
result.migrationsPath,
|
|
6154
|
-
"recurrent"
|
|
6155
|
-
);
|
|
6156
|
-
}
|
|
6157
|
-
if ("recurrentPath" in result && !path.isAbsolute(result.recurrentPath)) {
|
|
6158
|
-
result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
|
|
6159
|
-
}
|
|
6160
|
-
if ("baseTable" in config && config.baseTable) {
|
|
6161
|
-
const { types, snakeCase, language } = config.baseTable.prototype;
|
|
6162
|
-
result.columnTypes = types || makeColumnTypes(defaultSchemaConfig);
|
|
6163
|
-
if (snakeCase) result.snakeCase = true;
|
|
6164
|
-
if (language) result.language = language;
|
|
6165
|
-
} else {
|
|
6166
|
-
const ct = "columnTypes" in config && config.columnTypes;
|
|
6167
|
-
result.columnTypes = (typeof ct === "function" ? ct(
|
|
6168
|
-
makeColumnTypes(defaultSchemaConfig)
|
|
6169
|
-
) : ct) || makeColumnTypes(defaultSchemaConfig);
|
|
6170
|
-
}
|
|
6171
|
-
if (config.migrationId === "serial") {
|
|
6172
|
-
result.migrationId = { serial: 4 };
|
|
6173
|
-
}
|
|
6174
|
-
const transaction = getCliParam(args, "transaction");
|
|
6175
|
-
if (transaction) {
|
|
6176
|
-
if (transaction !== "single" && transaction !== "per-migration") {
|
|
6177
|
-
throw new Error(
|
|
6178
|
-
`Unsupported transaction param ${transaction}, expected single or per-migration`
|
|
6179
|
-
);
|
|
6099
|
+
foreignColumns: references.foreignColumns,
|
|
6100
|
+
options: {
|
|
6101
|
+
match: matchMap[references.match],
|
|
6102
|
+
onUpdate: fkeyActionMap[references.onUpdate],
|
|
6103
|
+
onDelete: fkeyActionMap[references.onDelete]
|
|
6104
|
+
}
|
|
6105
|
+
} : void 0,
|
|
6106
|
+
check: check ? raw({ raw: check.expression }) : void 0
|
|
6107
|
+
};
|
|
6108
|
+
const name = item.name && item.name !== getConstraintName(table.name, constraint, ctx.snakeCase) ? item.name : void 0;
|
|
6109
|
+
if (name) {
|
|
6110
|
+
constraint.name = name;
|
|
6111
|
+
if (constraint.references?.options) {
|
|
6112
|
+
constraint.references.options.name = name;
|
|
6180
6113
|
}
|
|
6181
|
-
result.transaction = transaction;
|
|
6182
|
-
} else if (!result.transaction) {
|
|
6183
|
-
result.transaction = "single";
|
|
6184
6114
|
}
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6115
|
+
return constraint;
|
|
6116
|
+
};
|
|
6117
|
+
const makeIndexOrExcludeOptions = (tableName, index, key) => {
|
|
6118
|
+
return {
|
|
6119
|
+
name: index.name !== (key === "indexes" ? getIndexName : getExcludeName)(
|
|
6120
|
+
tableName,
|
|
6121
|
+
index.columns
|
|
6122
|
+
) ? index.name : void 0,
|
|
6123
|
+
using: index.using === "btree" ? void 0 : index.using,
|
|
6124
|
+
unique: index.unique || void 0,
|
|
6125
|
+
include: index.include,
|
|
6126
|
+
nullsNotDistinct: index.nullsNotDistinct || void 0,
|
|
6127
|
+
with: index.with,
|
|
6128
|
+
tablespace: index.tablespace,
|
|
6129
|
+
where: index.where
|
|
6130
|
+
};
|
|
6131
|
+
};
|
|
6132
|
+
const checkIfIsOuterRecursiveFkey = (data, table, references) => {
|
|
6133
|
+
const referencesId = `${references.foreignSchema}.${references.foreignTable}`;
|
|
6134
|
+
const tableId = `${table.schemaName}.${table.name}`;
|
|
6135
|
+
for (const other of data.tables) {
|
|
6136
|
+
const id = `${other.schemaName}.${other.name}`;
|
|
6137
|
+
if (referencesId === id) {
|
|
6138
|
+
for (const c of data.constraints) {
|
|
6139
|
+
if (c.tableName === other.name && c.schemaName === other.schemaName && c.references?.foreignTable === table.name && c.references.foreignSchema === table.schemaName && tableId < id) {
|
|
6140
|
+
return true;
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
break;
|
|
6192
6144
|
}
|
|
6193
6145
|
}
|
|
6194
|
-
|
|
6195
|
-
|
|
6146
|
+
return false;
|
|
6147
|
+
};
|
|
6148
|
+
|
|
6149
|
+
const pullDbStructure = async (adapter, config) => {
|
|
6150
|
+
const currentSchema = adapter.searchPath || "public";
|
|
6151
|
+
const ctx = makeStructureToAstCtx(config, currentSchema);
|
|
6152
|
+
const ast = await structureToAst(ctx, adapter, config);
|
|
6153
|
+
const result = astToMigration(currentSchema, config, ast);
|
|
6154
|
+
if (!result) return;
|
|
6155
|
+
const version = await makeFileVersion({}, config);
|
|
6156
|
+
await writeMigrationFile(config, version, "pull", result);
|
|
6157
|
+
const silentQueries = Object.assign(adapter, {
|
|
6158
|
+
silentQuery: adapter.query,
|
|
6159
|
+
silentArrays: adapter.arrays
|
|
6160
|
+
});
|
|
6161
|
+
await saveMigratedVersion(silentQueries, version, "pull", config);
|
|
6162
|
+
const unsupportedEntries = Object.entries(ctx.unsupportedTypes);
|
|
6163
|
+
const len = unsupportedEntries.length;
|
|
6164
|
+
if (len) {
|
|
6165
|
+
let count = 0;
|
|
6166
|
+
config.logger?.warn(
|
|
6167
|
+
`Found unsupported types:
|
|
6168
|
+
${unsupportedEntries.map(([type, columns]) => {
|
|
6169
|
+
count += columns.length;
|
|
6170
|
+
return `- ${type} is used for column${columns.length > 1 ? "s" : ""} ${columns.join(", ")}`;
|
|
6171
|
+
}).join("\n")}
|
|
6172
|
+
Append \`as\` method manually to ${count > 1 ? "these" : "this"} column${count > 1 ? "s" : ""} to treat ${count > 1 ? "them" : "it"} as other column type`
|
|
6173
|
+
);
|
|
6174
|
+
}
|
|
6175
|
+
config.logger?.log("Database pulled successfully");
|
|
6196
6176
|
};
|
|
6197
6177
|
|
|
6198
6178
|
const listMigrationsStatuses = async (adapters, config, params) => {
|
|
@@ -6358,85 +6338,275 @@ const rebase = async (adapters, config) => {
|
|
|
6358
6338
|
renames.push(values);
|
|
6359
6339
|
renamesMap[file.path] = values;
|
|
6360
6340
|
}
|
|
6361
|
-
if (moveFile === prev) {
|
|
6362
|
-
if (prev.serial < minVersionToMigrate)
|
|
6363
|
-
minVersionToMigrate = prev.serial;
|
|
6364
|
-
newVersion = prev.serial + move;
|
|
6365
|
-
let item = [prev.path, newVersion];
|
|
6366
|
-
if (renamesMap[prev.path]) {
|
|
6367
|
-
renamesMap[prev.path] = item;
|
|
6368
|
-
for (let i2 = renames.length - 1; i2 >= 0; i2--) {
|
|
6369
|
-
const rename = renames[i2];
|
|
6370
|
-
rename[1]--;
|
|
6371
|
-
renames[i2] = item;
|
|
6372
|
-
if (rename[0] === prev.path) break;
|
|
6373
|
-
renamesMap[item[0]] = item;
|
|
6374
|
-
item = rename;
|
|
6375
|
-
}
|
|
6376
|
-
} else {
|
|
6377
|
-
renames.push(item);
|
|
6378
|
-
renamesMap[prev.path] = item;
|
|
6379
|
-
}
|
|
6341
|
+
if (moveFile === prev) {
|
|
6342
|
+
if (prev.serial < minVersionToMigrate)
|
|
6343
|
+
minVersionToMigrate = prev.serial;
|
|
6344
|
+
newVersion = prev.serial + move;
|
|
6345
|
+
let item = [prev.path, newVersion];
|
|
6346
|
+
if (renamesMap[prev.path]) {
|
|
6347
|
+
renamesMap[prev.path] = item;
|
|
6348
|
+
for (let i2 = renames.length - 1; i2 >= 0; i2--) {
|
|
6349
|
+
const rename = renames[i2];
|
|
6350
|
+
rename[1]--;
|
|
6351
|
+
renames[i2] = item;
|
|
6352
|
+
if (rename[0] === prev.path) break;
|
|
6353
|
+
renamesMap[item[0]] = item;
|
|
6354
|
+
item = rename;
|
|
6355
|
+
}
|
|
6356
|
+
} else {
|
|
6357
|
+
renames.push(item);
|
|
6358
|
+
renamesMap[prev.path] = item;
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
}
|
|
6362
|
+
if (file.name !== migratedName && newVersion > maxNewVersion) {
|
|
6363
|
+
maxNewVersion = newVersion;
|
|
6364
|
+
}
|
|
6365
|
+
}
|
|
6366
|
+
if (!renames.length && !migratedFiles.length) return;
|
|
6367
|
+
maxNewVersion++;
|
|
6368
|
+
renames.push(
|
|
6369
|
+
...migratedFiles.map((file, i) => {
|
|
6370
|
+
const rename = [file.path, maxNewVersion + i];
|
|
6371
|
+
renamesMap[file.path] = rename;
|
|
6372
|
+
return rename;
|
|
6373
|
+
})
|
|
6374
|
+
);
|
|
6375
|
+
if (!renames.length) return;
|
|
6376
|
+
const migrationsDown = files.filter(
|
|
6377
|
+
(file) => combinedVersionsMap[file.version] === file.name && file.serial >= minVersionToMigrate
|
|
6378
|
+
);
|
|
6379
|
+
const migrationsUp = files.reduce((files2, file) => {
|
|
6380
|
+
const rename = renamesMap[file.path];
|
|
6381
|
+
if (rename) {
|
|
6382
|
+
const version = String(rename[1]).padStart(4, "0");
|
|
6383
|
+
files2.push({
|
|
6384
|
+
...file,
|
|
6385
|
+
path: path.join(
|
|
6386
|
+
path.dirname(rename[0]),
|
|
6387
|
+
version + path.basename(rename[0]).slice(version.length)
|
|
6388
|
+
),
|
|
6389
|
+
version
|
|
6390
|
+
});
|
|
6391
|
+
} else if (!combinedVersionsMap[file.version] || file.serial >= minVersionToMigrate) {
|
|
6392
|
+
files2.push(file);
|
|
6393
|
+
}
|
|
6394
|
+
return files2;
|
|
6395
|
+
}, []).sort((a, b) => +b.version - +a.version);
|
|
6396
|
+
set.migrations = migrationsDown;
|
|
6397
|
+
const redoConfig = {
|
|
6398
|
+
...config,
|
|
6399
|
+
async afterRollback() {
|
|
6400
|
+
set.migrations = migrationsUp;
|
|
6401
|
+
},
|
|
6402
|
+
async afterMigrate() {
|
|
6403
|
+
set.migrations = migrationsDown;
|
|
6404
|
+
}
|
|
6405
|
+
};
|
|
6406
|
+
for (const adapter of adapters) {
|
|
6407
|
+
await redo(adapter, redoConfig, { ctx, count: Infinity });
|
|
6408
|
+
}
|
|
6409
|
+
for (let i = renames.length - 1; i >= 0; i--) {
|
|
6410
|
+
const [from, version] = renames[i];
|
|
6411
|
+
const prefix = String(version).padStart(4, "0");
|
|
6412
|
+
await fs.rename(
|
|
6413
|
+
from,
|
|
6414
|
+
path.join(
|
|
6415
|
+
path.dirname(from),
|
|
6416
|
+
prefix + path.basename(from).slice(prefix.length)
|
|
6417
|
+
)
|
|
6418
|
+
);
|
|
6419
|
+
}
|
|
6420
|
+
};
|
|
6421
|
+
|
|
6422
|
+
const close = (adapters) => Promise.all(adapters.map((adapter) => adapter.close()));
|
|
6423
|
+
const maybeRunRecurrent = async (adapters, config) => {
|
|
6424
|
+
config.recurrentPath && await runRecurrentMigrations(
|
|
6425
|
+
adapters,
|
|
6426
|
+
config
|
|
6427
|
+
);
|
|
6428
|
+
};
|
|
6429
|
+
const rakeDbAliases$1 = {
|
|
6430
|
+
migrate: "up",
|
|
6431
|
+
rollback: "down",
|
|
6432
|
+
s: "status",
|
|
6433
|
+
rec: "recurrent"
|
|
6434
|
+
};
|
|
6435
|
+
const upCommand = {
|
|
6436
|
+
run: (adapters, config, args) => migrateCommand(adapters, config, args).then(() => maybeRunRecurrent(adapters, config)).then(() => close(adapters)),
|
|
6437
|
+
help: "migrate pending migrations",
|
|
6438
|
+
helpArguments: {
|
|
6439
|
+
"no arguments": "migrate all pending",
|
|
6440
|
+
"a number": "run a specific number of pending migrations",
|
|
6441
|
+
force: "enforce migrating a pending file in the middle"
|
|
6442
|
+
}
|
|
6443
|
+
};
|
|
6444
|
+
const downCommand = {
|
|
6445
|
+
run: (adapters, config, args) => rollbackCommand(adapters, config, args).then(() => close(adapters)),
|
|
6446
|
+
help: "rollback migrated migrations",
|
|
6447
|
+
helpArguments: {
|
|
6448
|
+
"no arguments": "rollback one last migration",
|
|
6449
|
+
"a number": "rollback a specified number",
|
|
6450
|
+
all: "rollback all migrations"
|
|
6451
|
+
}
|
|
6452
|
+
};
|
|
6453
|
+
const statusCommand = {
|
|
6454
|
+
run(adapters, config, args) {
|
|
6455
|
+
const showUrl = args.includes("p") || args.includes("path");
|
|
6456
|
+
return listMigrationsStatuses(adapters, config, { showUrl });
|
|
6457
|
+
},
|
|
6458
|
+
help: "list migrations statuses",
|
|
6459
|
+
helpArguments: {
|
|
6460
|
+
"no arguments": `does not print file paths`,
|
|
6461
|
+
"p, path": "also print file paths"
|
|
6462
|
+
}
|
|
6463
|
+
};
|
|
6464
|
+
const recurrent = {
|
|
6465
|
+
async run(adapters, config) {
|
|
6466
|
+
if (!config.recurrentPath) return;
|
|
6467
|
+
await maybeRunRecurrent(adapters, config).then(() => close(adapters));
|
|
6468
|
+
},
|
|
6469
|
+
help: "run recurrent migrations"
|
|
6470
|
+
};
|
|
6471
|
+
const rakeDbCommands = {
|
|
6472
|
+
create: {
|
|
6473
|
+
run: (adapters, config) => createDatabaseCommand(adapters, config),
|
|
6474
|
+
help: "create databases"
|
|
6475
|
+
},
|
|
6476
|
+
drop: {
|
|
6477
|
+
run: dropDatabaseCommand,
|
|
6478
|
+
help: "drop databases"
|
|
6479
|
+
},
|
|
6480
|
+
reset: {
|
|
6481
|
+
run: (adapters, config) => resetDatabaseCommand(adapters, config),
|
|
6482
|
+
help: "drop, create and migrate databases"
|
|
6483
|
+
},
|
|
6484
|
+
up: upCommand,
|
|
6485
|
+
down: downCommand,
|
|
6486
|
+
redo: {
|
|
6487
|
+
run: (adapters, config, args) => redoCommand(adapters, config, args).then(() => maybeRunRecurrent(adapters, config)).then(() => close(adapters)),
|
|
6488
|
+
help: "rollback and migrate, run recurrent"
|
|
6489
|
+
},
|
|
6490
|
+
pull: {
|
|
6491
|
+
run: ([adapter], config) => pullDbStructure(adapter, config).then(() => close([adapter])),
|
|
6492
|
+
help: "generate a combined migration for an existing database"
|
|
6493
|
+
},
|
|
6494
|
+
new: {
|
|
6495
|
+
run(_, config, args) {
|
|
6496
|
+
const [name] = args;
|
|
6497
|
+
if (!name) throw new Error("Migration name is missing");
|
|
6498
|
+
return newMigration(config, name);
|
|
6499
|
+
},
|
|
6500
|
+
help: "create new migration file"
|
|
6501
|
+
},
|
|
6502
|
+
status: statusCommand,
|
|
6503
|
+
recurrent,
|
|
6504
|
+
rebase: {
|
|
6505
|
+
run: (adapters, config) => rebase(adapters, config).then(() => close(adapters)),
|
|
6506
|
+
help: "move local migrations below the new ones from upstream"
|
|
6507
|
+
},
|
|
6508
|
+
"change-ids": {
|
|
6509
|
+
run(adapters, config, [format, digitsArg]) {
|
|
6510
|
+
if (format !== "serial" && format !== "timestamp") {
|
|
6511
|
+
throw new Error(
|
|
6512
|
+
`Pass "serial" or "timestamp" argument to the "change-ids" command`
|
|
6513
|
+
);
|
|
6514
|
+
}
|
|
6515
|
+
const digits = digitsArg ? parseInt(digitsArg) : void 0;
|
|
6516
|
+
if (digits && isNaN(digits)) {
|
|
6517
|
+
throw new Error(`Second argument is optional and must be an integer`);
|
|
6380
6518
|
}
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6519
|
+
return changeIds(adapters, config, { format, digits });
|
|
6520
|
+
},
|
|
6521
|
+
help: "change migrations ids format",
|
|
6522
|
+
helpArguments: {
|
|
6523
|
+
serial: "change ids to 4 digit serial",
|
|
6524
|
+
"serial *number*": "change ids to serial number of custom length",
|
|
6525
|
+
timestamp: "change timestamps"
|
|
6384
6526
|
}
|
|
6385
6527
|
}
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
)
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
const
|
|
6528
|
+
};
|
|
6529
|
+
for (const key in rakeDbAliases$1) {
|
|
6530
|
+
const command = rakeDbAliases$1[key];
|
|
6531
|
+
if (command) rakeDbCommands[key] = rakeDbCommands[command];
|
|
6532
|
+
}
|
|
6533
|
+
let intermediateCallers = 0;
|
|
6534
|
+
const incrementIntermediateCaller = () => {
|
|
6535
|
+
intermediateCallers++;
|
|
6536
|
+
};
|
|
6537
|
+
const ensureBasePathAndDbScript = (config, intermediateCallers2 = 0) => {
|
|
6538
|
+
if (config.basePath && config.dbScript) return config;
|
|
6539
|
+
let filePath = getStackTrace()?.[3 + intermediateCallers2]?.getFileName();
|
|
6540
|
+
if (!filePath) {
|
|
6541
|
+
throw new Error(
|
|
6542
|
+
"Failed to determine path to db script. Please set basePath option of rakeDb"
|
|
6543
|
+
);
|
|
6544
|
+
}
|
|
6545
|
+
if (filePath.startsWith("file://")) {
|
|
6546
|
+
filePath = fileURLToPath(filePath);
|
|
6547
|
+
}
|
|
6548
|
+
const ext = path.extname(filePath);
|
|
6549
|
+
if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
|
|
6550
|
+
throw new Error(
|
|
6551
|
+
`Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
|
|
6552
|
+
);
|
|
6553
|
+
}
|
|
6554
|
+
config.basePath = path.dirname(filePath);
|
|
6555
|
+
config.dbScript = path.basename(filePath);
|
|
6556
|
+
return config;
|
|
6557
|
+
};
|
|
6558
|
+
const makeRakeDbConfig = (config, args) => {
|
|
6559
|
+
const ic = intermediateCallers;
|
|
6560
|
+
intermediateCallers = 0;
|
|
6561
|
+
const result = {
|
|
6562
|
+
...rakeDbConfigDefaults,
|
|
6418
6563
|
...config,
|
|
6419
|
-
|
|
6420
|
-
set.migrations = migrationsUp;
|
|
6421
|
-
},
|
|
6422
|
-
async afterMigrate() {
|
|
6423
|
-
set.migrations = migrationsDown;
|
|
6424
|
-
}
|
|
6564
|
+
__rakeDbConfig: true
|
|
6425
6565
|
};
|
|
6426
|
-
|
|
6427
|
-
|
|
6566
|
+
ensureBasePathAndDbScript(result, ic);
|
|
6567
|
+
Object.assign(result, processMigrateConfig(result));
|
|
6568
|
+
if (!result.recurrentPath && result.migrationsPath) {
|
|
6569
|
+
result.recurrentPath = path.join(result.migrationsPath, "recurrent");
|
|
6428
6570
|
}
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6571
|
+
if (result.recurrentPath && !path.isAbsolute(result.recurrentPath)) {
|
|
6572
|
+
result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
|
|
6573
|
+
}
|
|
6574
|
+
if ("baseTable" in config && config.baseTable) {
|
|
6575
|
+
const { types, snakeCase, language } = config.baseTable.prototype;
|
|
6576
|
+
result.columnTypes = types || makeColumnTypes(defaultSchemaConfig);
|
|
6577
|
+
if (snakeCase) result.snakeCase = true;
|
|
6578
|
+
if (language) result.language = language;
|
|
6579
|
+
} else {
|
|
6580
|
+
const ct = "columnTypes" in config && config.columnTypes;
|
|
6581
|
+
result.columnTypes = (typeof ct === "function" ? ct(
|
|
6582
|
+
makeColumnTypes(defaultSchemaConfig)
|
|
6583
|
+
) : ct) || makeColumnTypes(defaultSchemaConfig);
|
|
6584
|
+
}
|
|
6585
|
+
if (config.migrationId === "serial") {
|
|
6586
|
+
result.migrationId = { serial: 4 };
|
|
6587
|
+
}
|
|
6588
|
+
const transaction = getCliParam(args, "transaction");
|
|
6589
|
+
if (transaction) {
|
|
6590
|
+
if (transaction !== "single" && transaction !== "per-migration") {
|
|
6591
|
+
throw new Error(
|
|
6592
|
+
`Unsupported transaction param ${transaction}, expected single or per-migration`
|
|
6593
|
+
);
|
|
6594
|
+
}
|
|
6595
|
+
result.transaction = transaction;
|
|
6596
|
+
} else if (!result.transaction) {
|
|
6597
|
+
result.transaction = "single";
|
|
6598
|
+
}
|
|
6599
|
+
let c = rakeDbCommands;
|
|
6600
|
+
if (config.commands) {
|
|
6601
|
+
c = { ...c };
|
|
6602
|
+
const commands = config.commands;
|
|
6603
|
+
for (const key in commands) {
|
|
6604
|
+
const command = commands[key];
|
|
6605
|
+
c[key] = typeof command === "function" ? { run: command } : command;
|
|
6606
|
+
}
|
|
6439
6607
|
}
|
|
6608
|
+
result.commands = c;
|
|
6609
|
+
return result;
|
|
6440
6610
|
};
|
|
6441
6611
|
|
|
6442
6612
|
const rakeDbAliases = {
|
|
@@ -6454,7 +6624,7 @@ const rakeDbCliWithAdapter = (inputConfig, args = process.argv.slice(2)) => {
|
|
|
6454
6624
|
config = makeRakeDbConfig(inputConfig, args);
|
|
6455
6625
|
}
|
|
6456
6626
|
return {
|
|
6457
|
-
change:
|
|
6627
|
+
change: createMigrationChangeFn(config),
|
|
6458
6628
|
async run(adapter, runArgs) {
|
|
6459
6629
|
const adapters = toArray(adapter);
|
|
6460
6630
|
try {
|
|
@@ -6548,111 +6718,6 @@ ${Object.entries(helpArguments).map(
|
|
|
6548
6718
|
`);
|
|
6549
6719
|
}
|
|
6550
6720
|
};
|
|
6551
|
-
const close = (adapters) => Promise.all(adapters.map((adapter) => adapter.close()));
|
|
6552
|
-
const maybeRunRecurrent = async (adapters, config) => {
|
|
6553
|
-
config.recurrentPath && await runRecurrentMigrations(
|
|
6554
|
-
adapters,
|
|
6555
|
-
config
|
|
6556
|
-
);
|
|
6557
|
-
};
|
|
6558
|
-
const upCommand = {
|
|
6559
|
-
run: (adapters, config, args) => migrateCommand(adapters, config, args).then(() => maybeRunRecurrent(adapters, config)).then(() => close(adapters)),
|
|
6560
|
-
help: "migrate pending migrations",
|
|
6561
|
-
helpArguments: {
|
|
6562
|
-
"no arguments": "migrate all pending",
|
|
6563
|
-
"a number": "run a specific number of pending migrations",
|
|
6564
|
-
force: "enforce migrating a pending file in the middle"
|
|
6565
|
-
}
|
|
6566
|
-
};
|
|
6567
|
-
const downCommand = {
|
|
6568
|
-
run: (adapters, config, args) => rollbackCommand(adapters, config, args).then(() => close(adapters)),
|
|
6569
|
-
help: "rollback migrated migrations",
|
|
6570
|
-
helpArguments: {
|
|
6571
|
-
"no arguments": "rollback one last migration",
|
|
6572
|
-
"a number": "rollback a specified number",
|
|
6573
|
-
all: "rollback all migrations"
|
|
6574
|
-
}
|
|
6575
|
-
};
|
|
6576
|
-
const statusCommand = {
|
|
6577
|
-
run(adapters, config, args) {
|
|
6578
|
-
const showUrl = args.includes("p") || args.includes("path");
|
|
6579
|
-
return listMigrationsStatuses(adapters, config, { showUrl });
|
|
6580
|
-
},
|
|
6581
|
-
help: "list migrations statuses",
|
|
6582
|
-
helpArguments: {
|
|
6583
|
-
"no arguments": `does not print file paths`,
|
|
6584
|
-
"p, path": "also print file paths"
|
|
6585
|
-
}
|
|
6586
|
-
};
|
|
6587
|
-
const recurrent = {
|
|
6588
|
-
async run(adapters, config) {
|
|
6589
|
-
if (!config.recurrentPath) return;
|
|
6590
|
-
await maybeRunRecurrent(adapters, config).then(() => close(adapters));
|
|
6591
|
-
},
|
|
6592
|
-
help: "run recurrent migrations"
|
|
6593
|
-
};
|
|
6594
|
-
const rakeDbCommands = {
|
|
6595
|
-
create: {
|
|
6596
|
-
run: (adapters, config) => createDatabaseCommand(adapters, config),
|
|
6597
|
-
help: "create databases"
|
|
6598
|
-
},
|
|
6599
|
-
drop: {
|
|
6600
|
-
run: dropDatabaseCommand,
|
|
6601
|
-
help: "drop databases"
|
|
6602
|
-
},
|
|
6603
|
-
reset: {
|
|
6604
|
-
run: (adapters, config) => resetDatabaseCommand(adapters, config),
|
|
6605
|
-
help: "drop, create and migrate databases"
|
|
6606
|
-
},
|
|
6607
|
-
up: upCommand,
|
|
6608
|
-
down: downCommand,
|
|
6609
|
-
redo: {
|
|
6610
|
-
run: (adapters, config, args) => redoCommand(adapters, config, args).then(() => maybeRunRecurrent(adapters, config)).then(() => close(adapters)),
|
|
6611
|
-
help: "rollback and migrate, run recurrent"
|
|
6612
|
-
},
|
|
6613
|
-
pull: {
|
|
6614
|
-
run: ([adapter], config) => pullDbStructure(adapter, config).then(() => close([adapter])),
|
|
6615
|
-
help: "generate a combined migration for an existing database"
|
|
6616
|
-
},
|
|
6617
|
-
new: {
|
|
6618
|
-
run(_, config, args) {
|
|
6619
|
-
const [name] = args;
|
|
6620
|
-
if (!name) throw new Error("Migration name is missing");
|
|
6621
|
-
return newMigration(config, name);
|
|
6622
|
-
},
|
|
6623
|
-
help: "create new migration file"
|
|
6624
|
-
},
|
|
6625
|
-
status: statusCommand,
|
|
6626
|
-
recurrent,
|
|
6627
|
-
rebase: {
|
|
6628
|
-
run: (adapters, config) => rebase(adapters, config).then(() => close(adapters)),
|
|
6629
|
-
help: "move local migrations below the new ones from upstream"
|
|
6630
|
-
},
|
|
6631
|
-
"change-ids": {
|
|
6632
|
-
run(adapters, config, [format, digitsArg]) {
|
|
6633
|
-
if (format !== "serial" && format !== "timestamp") {
|
|
6634
|
-
throw new Error(
|
|
6635
|
-
`Pass "serial" or "timestamp" argument to the "change-ids" command`
|
|
6636
|
-
);
|
|
6637
|
-
}
|
|
6638
|
-
const digits = digitsArg ? parseInt(digitsArg) : void 0;
|
|
6639
|
-
if (digits && isNaN(digits)) {
|
|
6640
|
-
throw new Error(`Second argument is optional and must be an integer`);
|
|
6641
|
-
}
|
|
6642
|
-
return changeIds(adapters, config, { format, digits });
|
|
6643
|
-
},
|
|
6644
|
-
help: "change migrations ids format",
|
|
6645
|
-
helpArguments: {
|
|
6646
|
-
serial: "change ids to 4 digit serial",
|
|
6647
|
-
"serial *number*": "change ids to serial number of custom length",
|
|
6648
|
-
timestamp: "change ids to timestamps"
|
|
6649
|
-
}
|
|
6650
|
-
}
|
|
6651
|
-
};
|
|
6652
|
-
for (const key in rakeDbAliases) {
|
|
6653
|
-
const command = rakeDbAliases[key];
|
|
6654
|
-
if (command) rakeDbCommands[key] = rakeDbCommands[command];
|
|
6655
|
-
}
|
|
6656
6721
|
|
|
6657
|
-
export { RakeDbError, astToMigration, concatSchemaAndName, createDatabase, createMigrationInterface, createMigrationsSchemaAndTable, createSchema
|
|
6722
|
+
export { RakeDbError, astToMigration, concatSchemaAndName, createDatabase, createMigrationChangeFn, createMigrationInterface, createMigrationsSchemaAndTable, createSchema, createTable, dbColumnToAst, dropDatabase, dropSchema, dropTable, encodeColumnDefault, getConstraintName, getDbStructureTableData, getDbTableColumnsChecks, getDbVersion, getExcludeName, getIndexName, getMigrationsSchemaAndTable, getSchemaAndTableFromName, incrementIntermediateCaller, instantiateDbColumn, introspectDbSchema, makeDomainsMap, makeFileVersion, makeStructureToAstCtx, migrate, migrateAndClose, promptSelect, rakeDbCliWithAdapter, rakeDbCommands, rakeDbConfigDefaults, redo, rollback, runMigration, saveMigratedVersion, setRakeDbCliRunFn, structureToAst, tableToAst, writeMigrationFile };
|
|
6658
6723
|
//# sourceMappingURL=index.mjs.map
|