rake-db 2.30.9 → 2.31.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.d.ts +172 -98
- package/dist/index.js +987 -935
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +732 -680
- 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 +24 -21
package/dist/index.mjs
CHANGED
|
@@ -1,247 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { singleQuote, makeColumnTypes, defaultSchemaConfig, isRawSQL, escapeForMigration, ArrayColumn, toSnakeCase, toCamelCase, DomainColumn, toArray, EnumColumn, snakeCaseKey, getColumnTypes, parseTableData, emptyObject, escapeString, tableDataMethods, setDefaultLanguage, consumeColumnName, setCurrentColumnName, Column, parseTableDataInput, UnknownColumn, deepCompare, raw, logParamToLogObject, getImportPath, pathToLog, emptyArray, colors, exhaustive, codeToString, addCode, backtickQuote, rawSqlToCode, referencesArgsToCode, quoteObjectKey, primaryKeyInnerToCode, indexInnerToCode, excludeInnerToCode, constraintInnerToCode, pushTableDataCode, TimestampTZColumn, TimestampColumn, RawSql, CustomTypeColumn, assignDbDataToColumn, makeColumnsByType, PostgisGeographyPointColumn, getStackTrace } from 'pqb/internal';
|
|
2
2
|
import path, { join } from 'path';
|
|
3
3
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
4
|
+
import { createDbWithAdapter } from 'pqb';
|
|
4
5
|
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");
|
|
6
|
+
import path$1 from 'node:path';
|
|
245
7
|
|
|
246
8
|
const RAKE_DB_LOCK_KEY = "8582141715823621641";
|
|
247
9
|
const getFirstWordAndRest = (input) => {
|
|
@@ -330,10 +92,13 @@ const getCliParam = (args, name) => {
|
|
|
330
92
|
return;
|
|
331
93
|
};
|
|
332
94
|
|
|
333
|
-
const
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
95
|
+
const createMigrationChangeFn = (config) => {
|
|
96
|
+
const conf = config.columnTypes ? config : { columnTypes: makeColumnTypes(defaultSchemaConfig) };
|
|
97
|
+
return (fn) => {
|
|
98
|
+
const change = { fn, config: conf };
|
|
99
|
+
pushChange(change);
|
|
100
|
+
return change;
|
|
101
|
+
};
|
|
337
102
|
};
|
|
338
103
|
let currentChanges = [];
|
|
339
104
|
const clearChanges = () => {
|
|
@@ -394,7 +159,6 @@ const columnToSql = (schema, name, item, values, hasMultiplePrimaryKeys, snakeCa
|
|
|
394
159
|
referencesToSql(
|
|
395
160
|
schema,
|
|
396
161
|
{
|
|
397
|
-
columns: [name],
|
|
398
162
|
...foreignKey
|
|
399
163
|
},
|
|
400
164
|
snakeCase
|
|
@@ -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.
|
|
@@ -2506,7 +2280,6 @@ class Migration {
|
|
|
2506
2280
|
enumName
|
|
2507
2281
|
);
|
|
2508
2282
|
const ast = {
|
|
2509
|
-
type: "renameEnumValues",
|
|
2510
2283
|
schema,
|
|
2511
2284
|
name,
|
|
2512
2285
|
values
|
|
@@ -2920,12 +2693,9 @@ const addCheck = (migration, up, tableName, check) => {
|
|
|
2920
2693
|
...t.add(t.check(check))
|
|
2921
2694
|
}));
|
|
2922
2695
|
};
|
|
2923
|
-
const createSchema = async (migration, up, name) => {
|
|
2696
|
+
const createSchema$1 = async (migration, up, name) => {
|
|
2924
2697
|
const ast = {
|
|
2925
|
-
|
|
2926
|
-
action: up ? "create" : "drop",
|
|
2927
|
-
name
|
|
2928
|
-
};
|
|
2698
|
+
action: up ? "create" : "drop"};
|
|
2929
2699
|
await migration.adapter.query(
|
|
2930
2700
|
`${ast.action === "create" ? "CREATE" : "DROP"} SCHEMA "${name}"`
|
|
2931
2701
|
);
|
|
@@ -2936,7 +2706,6 @@ const createExtension = async (migration, up, fullName, options) => {
|
|
|
2936
2706
|
fullName
|
|
2937
2707
|
);
|
|
2938
2708
|
const ast = {
|
|
2939
|
-
type: "extension",
|
|
2940
2709
|
action: up ? "create" : "drop",
|
|
2941
2710
|
schema,
|
|
2942
2711
|
name,
|
|
@@ -2956,11 +2725,9 @@ const createEnum = async (migration, up, name, values, options = {}) => {
|
|
|
2956
2725
|
name
|
|
2957
2726
|
);
|
|
2958
2727
|
const ast = {
|
|
2959
|
-
type: "enum",
|
|
2960
2728
|
action: up ? "create" : "drop",
|
|
2961
2729
|
schema,
|
|
2962
2730
|
name: enumName,
|
|
2963
|
-
values,
|
|
2964
2731
|
...options
|
|
2965
2732
|
};
|
|
2966
2733
|
let query;
|
|
@@ -2978,7 +2745,6 @@ const createDomain = async (migration, up, name, fn) => {
|
|
|
2978
2745
|
name
|
|
2979
2746
|
);
|
|
2980
2747
|
const ast = {
|
|
2981
|
-
type: "domain",
|
|
2982
2748
|
action: up ? "create" : "drop",
|
|
2983
2749
|
schema,
|
|
2984
2750
|
name: domainName,
|
|
@@ -3011,7 +2777,6 @@ const createCollation = async (migration, up, name, options) => {
|
|
|
3011
2777
|
name
|
|
3012
2778
|
);
|
|
3013
2779
|
const ast = {
|
|
3014
|
-
type: "collation",
|
|
3015
2780
|
action: up ? "create" : "drop",
|
|
3016
2781
|
schema,
|
|
3017
2782
|
name: collationName,
|
|
@@ -3057,7 +2822,6 @@ const renameType = async (migration, from, to, kind) => {
|
|
|
3057
2822
|
migration.up ? to : from
|
|
3058
2823
|
);
|
|
3059
2824
|
const ast = {
|
|
3060
|
-
type: "renameType",
|
|
3061
2825
|
kind,
|
|
3062
2826
|
fromSchema,
|
|
3063
2827
|
from: f,
|
|
@@ -3096,7 +2860,6 @@ const addOrDropEnumValues = async (migration, up, enumName, values, options) =>
|
|
|
3096
2860
|
);
|
|
3097
2861
|
const quotedName = quoteTable(schema, name);
|
|
3098
2862
|
const ast = {
|
|
3099
|
-
type: "enumValues",
|
|
3100
2863
|
action: up ? "add" : "drop",
|
|
3101
2864
|
schema,
|
|
3102
2865
|
name,
|
|
@@ -3139,10 +2902,8 @@ const changeEnumValues = async (migration, enumName, fromValues, toValues) => {
|
|
|
3139
2902
|
toValues = values;
|
|
3140
2903
|
}
|
|
3141
2904
|
const ast = {
|
|
3142
|
-
type: "changeEnumValues",
|
|
3143
2905
|
schema,
|
|
3144
2906
|
name,
|
|
3145
|
-
fromValues,
|
|
3146
2907
|
toValues
|
|
3147
2908
|
};
|
|
3148
2909
|
await recreateEnum(
|
|
@@ -3406,7 +3167,7 @@ const getMigrations = async (ctx, config, up, allowDuplicates, getVersion = getM
|
|
|
3406
3167
|
function getMigrationsFromConfig(config, allowDuplicates, getVersion = getMigrationVersionOrThrow) {
|
|
3407
3168
|
const result = [];
|
|
3408
3169
|
const versions = {};
|
|
3409
|
-
const { migrations
|
|
3170
|
+
const { migrations } = config;
|
|
3410
3171
|
for (const key in migrations) {
|
|
3411
3172
|
const version = getVersion(config, path.basename(key));
|
|
3412
3173
|
if (versions[version] && !allowDuplicates) {
|
|
@@ -3416,7 +3177,7 @@ function getMigrationsFromConfig(config, allowDuplicates, getVersion = getMigrat
|
|
|
3416
3177
|
}
|
|
3417
3178
|
versions[version] = key;
|
|
3418
3179
|
result.push({
|
|
3419
|
-
path:
|
|
3180
|
+
path: key,
|
|
3420
3181
|
version,
|
|
3421
3182
|
load: migrations[key]
|
|
3422
3183
|
});
|
|
@@ -3466,7 +3227,7 @@ async function getMigrationsFromFiles(config, allowDuplicates, getVersion = getM
|
|
|
3466
3227
|
}
|
|
3467
3228
|
data.renameTo = {
|
|
3468
3229
|
to: config.migrationId,
|
|
3469
|
-
map: () => renameMigrationsMap(
|
|
3230
|
+
map: () => renameMigrationsMap(migrationsPath, file.name)
|
|
3470
3231
|
};
|
|
3471
3232
|
return data;
|
|
3472
3233
|
} else {
|
|
@@ -3505,8 +3266,8 @@ Run \`**db command** rebase\` to reorganize files with duplicated versions.`
|
|
|
3505
3266
|
result.migrations.sort(sortMigrationsAsc);
|
|
3506
3267
|
return result;
|
|
3507
3268
|
}
|
|
3508
|
-
const renameMigrationsMap = async (
|
|
3509
|
-
const filePath = path.join(
|
|
3269
|
+
const renameMigrationsMap = async (migrationsPath, fileName) => {
|
|
3270
|
+
const filePath = path.join(migrationsPath, fileName);
|
|
3510
3271
|
const json = await fs.readFile(filePath, "utf-8");
|
|
3511
3272
|
let data;
|
|
3512
3273
|
try {
|
|
@@ -3557,6 +3318,71 @@ function getDigitsPrefix(name) {
|
|
|
3557
3318
|
return value;
|
|
3558
3319
|
}
|
|
3559
3320
|
|
|
3321
|
+
const getMaybeTransactionAdapter = (db) => "$getAdapter" in db ? db.$getAdapter() : db;
|
|
3322
|
+
const runSqlInSavePoint = async (db, sql, code) => {
|
|
3323
|
+
const adapter = getMaybeTransactionAdapter(db);
|
|
3324
|
+
try {
|
|
3325
|
+
await adapter.query(
|
|
3326
|
+
adapter.isInTransaction() ? `SAVEPOINT s; ${sql}; RELEASE SAVEPOINT s` : sql
|
|
3327
|
+
);
|
|
3328
|
+
return "done";
|
|
3329
|
+
} catch (err) {
|
|
3330
|
+
if (err.code === code) {
|
|
3331
|
+
if (adapter.isInTransaction()) {
|
|
3332
|
+
await adapter.query(`ROLLBACK TO SAVEPOINT s`);
|
|
3333
|
+
}
|
|
3334
|
+
return "already";
|
|
3335
|
+
}
|
|
3336
|
+
throw err;
|
|
3337
|
+
}
|
|
3338
|
+
};
|
|
3339
|
+
|
|
3340
|
+
class CreateOrDropError extends Error {
|
|
3341
|
+
constructor(message, status, cause) {
|
|
3342
|
+
super(message);
|
|
3343
|
+
this.status = status;
|
|
3344
|
+
this.cause = cause;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
const createDatabase = async (db, {
|
|
3348
|
+
database,
|
|
3349
|
+
owner
|
|
3350
|
+
}) => {
|
|
3351
|
+
return createOrDrop(
|
|
3352
|
+
db,
|
|
3353
|
+
`CREATE DATABASE "${database}"${owner ? ` OWNER "${owner}"` : ""}`
|
|
3354
|
+
);
|
|
3355
|
+
};
|
|
3356
|
+
const dropDatabase = async (db, { database }) => {
|
|
3357
|
+
return createOrDrop(db, `DROP DATABASE "${database}"`);
|
|
3358
|
+
};
|
|
3359
|
+
const createOrDrop = async (db, sql) => {
|
|
3360
|
+
try {
|
|
3361
|
+
const adapter = getMaybeTransactionAdapter(db);
|
|
3362
|
+
await adapter.query(sql);
|
|
3363
|
+
return "done";
|
|
3364
|
+
} catch (error) {
|
|
3365
|
+
const err = error;
|
|
3366
|
+
if (typeof err.message === "string" && err.message.includes("sslmode=require")) {
|
|
3367
|
+
throw new CreateOrDropError("SSL required", "ssl-required", err);
|
|
3368
|
+
}
|
|
3369
|
+
if (err.code === "42P04" || err.code === "3D000") {
|
|
3370
|
+
return "already";
|
|
3371
|
+
}
|
|
3372
|
+
if (err.code === "42501") {
|
|
3373
|
+
throw new CreateOrDropError("Insufficient privilege", "forbidden", err);
|
|
3374
|
+
}
|
|
3375
|
+
if (typeof err.message === "string" && err.message.includes("password authentication failed")) {
|
|
3376
|
+
throw new CreateOrDropError("Authentication failed", "auth-failed", err);
|
|
3377
|
+
}
|
|
3378
|
+
throw err;
|
|
3379
|
+
}
|
|
3380
|
+
};
|
|
3381
|
+
const createSchema = async (db, sql) => runSqlInSavePoint(db, `CREATE SCHEMA ${sql}`, "42P06");
|
|
3382
|
+
const dropSchema = async (db, sql) => runSqlInSavePoint(db, `DROP SCHEMA ${sql}`, "3F000");
|
|
3383
|
+
const createTable = async (db, sql) => runSqlInSavePoint(db, `CREATE TABLE ${sql}`, "42P07");
|
|
3384
|
+
const dropTable = async (db, sql) => runSqlInSavePoint(db, `DROP TABLE ${sql}`, "42P01");
|
|
3385
|
+
|
|
3560
3386
|
const saveMigratedVersion = async (db, version, name, config) => {
|
|
3561
3387
|
await db.silentArrays(
|
|
3562
3388
|
`INSERT INTO ${migrationsSchemaTableSql(
|
|
@@ -3570,12 +3396,12 @@ const createMigrationsSchemaAndTable = async (db, config) => {
|
|
|
3570
3396
|
const adapter = getMaybeTransactionAdapter(db);
|
|
3571
3397
|
const { schema, table } = getMigrationsSchemaAndTable(adapter, config);
|
|
3572
3398
|
if (schema) {
|
|
3573
|
-
const res2 = await createSchema
|
|
3399
|
+
const res2 = await createSchema(db, schema);
|
|
3574
3400
|
if (res2 === "done") {
|
|
3575
3401
|
config.logger?.log(`Created schema "${schema}"`);
|
|
3576
3402
|
}
|
|
3577
3403
|
}
|
|
3578
|
-
const res = await createTable
|
|
3404
|
+
const res = await createTable(
|
|
3579
3405
|
db,
|
|
3580
3406
|
`${schema ? `"${schema}"."${table}"` : `"${table}"`} (version TEXT NOT NULL, name TEXT NOT NULL)`
|
|
3581
3407
|
);
|
|
@@ -3600,53 +3426,62 @@ const deleteMigratedVersion = async (adapter, version, name, config) => {
|
|
|
3600
3426
|
class NoMigrationsTableError extends Error {
|
|
3601
3427
|
}
|
|
3602
3428
|
const getMigratedVersionsMap = async (ctx, adapter, config, renameTo) => {
|
|
3429
|
+
const table = migrationsSchemaTableSql(adapter, config);
|
|
3430
|
+
const inTransaction = "isInTransaction" in adapter && adapter.isInTransaction();
|
|
3431
|
+
let result;
|
|
3603
3432
|
try {
|
|
3604
|
-
|
|
3605
|
-
|
|
3433
|
+
if (inTransaction) {
|
|
3434
|
+
await adapter.query(`SAVEPOINT check_migrations_table`);
|
|
3435
|
+
}
|
|
3436
|
+
result = await adapter.arrays(
|
|
3606
3437
|
`SELECT * FROM ${table} ORDER BY version`
|
|
3607
3438
|
);
|
|
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
|
-
);
|
|
3439
|
+
if (inTransaction) {
|
|
3440
|
+
await adapter.query(`RELEASE SAVEPOINT check_migrations_table`);
|
|
3637
3441
|
}
|
|
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
3442
|
} catch (err) {
|
|
3644
3443
|
if (err.code === "42P01") {
|
|
3444
|
+
if (inTransaction) {
|
|
3445
|
+
await adapter.query(`ROLLBACK TO SAVEPOINT check_migrations_table`);
|
|
3446
|
+
}
|
|
3645
3447
|
throw new NoMigrationsTableError();
|
|
3646
3448
|
} else {
|
|
3647
3449
|
throw err;
|
|
3648
3450
|
}
|
|
3649
3451
|
}
|
|
3452
|
+
if (!result.fields[1]) {
|
|
3453
|
+
const { migrations } = await getMigrations(ctx, config, true);
|
|
3454
|
+
const map = {};
|
|
3455
|
+
for (const item of migrations) {
|
|
3456
|
+
const name = path.basename(item.path);
|
|
3457
|
+
map[item.version] = name.slice(getDigitsPrefix(name).length + 1);
|
|
3458
|
+
}
|
|
3459
|
+
for (const row of result.rows) {
|
|
3460
|
+
const [version] = row;
|
|
3461
|
+
const name = map[version];
|
|
3462
|
+
if (!name) {
|
|
3463
|
+
throw new Error(
|
|
3464
|
+
`Migration for version ${version} is stored in db but is not found among available migrations`
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3467
|
+
row[1] = name;
|
|
3468
|
+
}
|
|
3469
|
+
await adapter.arrays(`ALTER TABLE ${table} ADD COLUMN name TEXT`);
|
|
3470
|
+
await Promise.all(
|
|
3471
|
+
result.rows.map(
|
|
3472
|
+
([version, name]) => adapter.arrays(`UPDATE ${table} SET name = $2 WHERE version = $1`, [
|
|
3473
|
+
version,
|
|
3474
|
+
name
|
|
3475
|
+
])
|
|
3476
|
+
)
|
|
3477
|
+
);
|
|
3478
|
+
await adapter.arrays(`ALTER TABLE ${table} ALTER COLUMN name SET NOT NULL`);
|
|
3479
|
+
}
|
|
3480
|
+
let versions = Object.fromEntries(result.rows);
|
|
3481
|
+
if (renameTo) {
|
|
3482
|
+
versions = await renameMigrations(config, adapter, versions, renameTo);
|
|
3483
|
+
}
|
|
3484
|
+
return { map: versions, sequence: result.rows.map((row) => +row[0]) };
|
|
3650
3485
|
};
|
|
3651
3486
|
async function renameMigrations(config, trx, versions, renameTo) {
|
|
3652
3487
|
let first;
|
|
@@ -3677,11 +3512,35 @@ async function renameMigrations(config, trx, versions, renameTo) {
|
|
|
3677
3512
|
return updatedVersions;
|
|
3678
3513
|
}
|
|
3679
3514
|
|
|
3515
|
+
const migrateConfigDefaults = {
|
|
3516
|
+
migrationId: { serial: 4 },
|
|
3517
|
+
migrationsTable: "schemaMigrations",
|
|
3518
|
+
transaction: "single"
|
|
3519
|
+
};
|
|
3520
|
+
const handleConfigLogger = (config) => {
|
|
3521
|
+
return config.log === true ? config.logger || console : config.log === false ? void 0 : config.logger;
|
|
3522
|
+
};
|
|
3523
|
+
const processMigrateConfig = (config) => {
|
|
3524
|
+
let migrationsPath;
|
|
3525
|
+
if (!("migrations" in config)) {
|
|
3526
|
+
migrationsPath = config.migrationsPath ? config.migrationsPath : path$1.join("src", "db", "migrations");
|
|
3527
|
+
if (config.basePath && !path$1.isAbsolute(migrationsPath)) {
|
|
3528
|
+
migrationsPath = path$1.resolve(config.basePath, migrationsPath);
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
return {
|
|
3532
|
+
...migrateConfigDefaults,
|
|
3533
|
+
...config,
|
|
3534
|
+
migrationsPath,
|
|
3535
|
+
logger: handleConfigLogger(config)
|
|
3536
|
+
};
|
|
3537
|
+
};
|
|
3680
3538
|
const transactionIfSingle = (adapter, config, fn) => {
|
|
3681
3539
|
return config.transaction === "single" ? transaction(adapter, config, fn) : fn(adapter);
|
|
3682
3540
|
};
|
|
3683
3541
|
function makeMigrateFn(up, defaultCount, fn) {
|
|
3684
|
-
return async (db,
|
|
3542
|
+
return async (db, publicConfig, params) => {
|
|
3543
|
+
const config = processMigrateConfig(publicConfig);
|
|
3685
3544
|
const ctx = params?.ctx || {};
|
|
3686
3545
|
const set = await getMigrations(ctx, config, up);
|
|
3687
3546
|
const count = params?.count ?? defaultCount;
|
|
@@ -3724,7 +3583,16 @@ function makeMigrateFn(up, defaultCount, fn) {
|
|
|
3724
3583
|
const migrate = makeMigrateFn(
|
|
3725
3584
|
true,
|
|
3726
3585
|
Infinity,
|
|
3727
|
-
(trx, config, set, versions, count, force) => migrateOrRollback(
|
|
3586
|
+
(trx, config, set, versions, count, force) => migrateOrRollback(
|
|
3587
|
+
trx,
|
|
3588
|
+
config,
|
|
3589
|
+
set,
|
|
3590
|
+
versions,
|
|
3591
|
+
count,
|
|
3592
|
+
true,
|
|
3593
|
+
false,
|
|
3594
|
+
force
|
|
3595
|
+
)
|
|
3728
3596
|
);
|
|
3729
3597
|
const migrateAndClose = async (db, config, params) => {
|
|
3730
3598
|
const adapter = getMaybeTransactionAdapter(db);
|
|
@@ -3732,26 +3600,46 @@ const migrateAndClose = async (db, config, params) => {
|
|
|
3732
3600
|
await adapter.close();
|
|
3733
3601
|
};
|
|
3734
3602
|
async function runMigration(db, ...args) {
|
|
3735
|
-
const [
|
|
3603
|
+
const [rawConfig, migration] = args.length === 1 ? [{}, args[0]] : [args[0], args[1]];
|
|
3604
|
+
const config = {
|
|
3605
|
+
...rawConfig,
|
|
3606
|
+
logger: handleConfigLogger(rawConfig)
|
|
3607
|
+
};
|
|
3736
3608
|
const adapter = getMaybeTransactionAdapter(db);
|
|
3737
3609
|
await transaction(adapter, config, async (trx) => {
|
|
3738
3610
|
clearChanges();
|
|
3739
3611
|
const changes = await getChanges({ load: migration });
|
|
3740
|
-
|
|
3741
|
-
await applyMigration(trx, true, changes, config2);
|
|
3612
|
+
await applyMigration(trx, true, changes, config);
|
|
3742
3613
|
});
|
|
3743
3614
|
}
|
|
3744
3615
|
const rollback = makeMigrateFn(
|
|
3745
3616
|
false,
|
|
3746
3617
|
1,
|
|
3747
|
-
(trx, config, set, versions, count, force) => migrateOrRollback(
|
|
3618
|
+
(trx, config, set, versions, count, force) => migrateOrRollback(
|
|
3619
|
+
trx,
|
|
3620
|
+
config,
|
|
3621
|
+
set,
|
|
3622
|
+
versions,
|
|
3623
|
+
count,
|
|
3624
|
+
false,
|
|
3625
|
+
false,
|
|
3626
|
+
force
|
|
3627
|
+
)
|
|
3748
3628
|
);
|
|
3749
3629
|
const redo = makeMigrateFn(
|
|
3750
3630
|
true,
|
|
3751
3631
|
1,
|
|
3752
3632
|
async (trx, config, set, versions, count, force) => {
|
|
3753
3633
|
set.migrations.reverse();
|
|
3754
|
-
await migrateOrRollback(
|
|
3634
|
+
await migrateOrRollback(
|
|
3635
|
+
trx,
|
|
3636
|
+
config,
|
|
3637
|
+
set,
|
|
3638
|
+
versions,
|
|
3639
|
+
count,
|
|
3640
|
+
false,
|
|
3641
|
+
true
|
|
3642
|
+
);
|
|
3755
3643
|
set.migrations.reverse();
|
|
3756
3644
|
return migrateOrRollback(
|
|
3757
3645
|
trx,
|
|
@@ -3822,7 +3710,7 @@ const migrateOrRollback = async (trx, config, set, versions, count, up, redo2, f
|
|
|
3822
3710
|
await changeMigratedVersion(adapter, up, file, config);
|
|
3823
3711
|
(migrations ?? (migrations = [])).push(file);
|
|
3824
3712
|
if (up) {
|
|
3825
|
-
const name = path.basename(file.path);
|
|
3713
|
+
const name = path$1.basename(file.path);
|
|
3826
3714
|
versionsMap[file.version] = name;
|
|
3827
3715
|
sequence.push(+file.version);
|
|
3828
3716
|
} else {
|
|
@@ -3869,7 +3757,7 @@ const checkMigrationOrder = (config, set, { sequence, map }, force) => {
|
|
|
3869
3757
|
if (version > last || map[file.version]) continue;
|
|
3870
3758
|
if (!force) {
|
|
3871
3759
|
throw new Error(
|
|
3872
|
-
`Cannot migrate ${path.basename(
|
|
3760
|
+
`Cannot migrate ${path$1.basename(
|
|
3873
3761
|
file.path
|
|
3874
3762
|
)} because the higher position ${map[versionToString(config, last)]} was already migrated.
|
|
3875
3763
|
Run \`**db command** up force\` to rollback the above migrations and migrate all`
|
|
@@ -3905,105 +3793,296 @@ const runMigrationInOwnTransaction = (adapter, up, changes, config) => {
|
|
|
3905
3793
|
);
|
|
3906
3794
|
};
|
|
3907
3795
|
const applyMigration = async (trx, up, changes, config) => {
|
|
3908
|
-
const
|
|
3796
|
+
const { adapter, getDb: getDb2 } = createMigrationInterface(trx, up, config);
|
|
3909
3797
|
if (changes.length) {
|
|
3910
3798
|
const from = up ? 0 : changes.length - 1;
|
|
3911
3799
|
const to = up ? changes.length : -1;
|
|
3912
3800
|
const step = up ? 1 : -1;
|
|
3913
3801
|
for (let i = from; i !== to; i += step) {
|
|
3914
|
-
|
|
3802
|
+
const change = changes[i];
|
|
3803
|
+
const db = getDb2(change.config.columnTypes);
|
|
3804
|
+
await change.fn(db, up);
|
|
3915
3805
|
}
|
|
3916
3806
|
}
|
|
3917
|
-
return
|
|
3807
|
+
return adapter;
|
|
3918
3808
|
};
|
|
3919
3809
|
const changeMigratedVersion = async (adapter, up, file, config) => {
|
|
3920
3810
|
await (up ? saveMigratedVersion : deleteMigratedVersion)(
|
|
3921
3811
|
adapter,
|
|
3922
3812
|
file.version,
|
|
3923
|
-
path.basename(file.path).slice(file.version.length + 1),
|
|
3813
|
+
path$1.basename(file.path).slice(file.version.length + 1),
|
|
3924
3814
|
config
|
|
3925
3815
|
);
|
|
3926
3816
|
};
|
|
3927
3817
|
|
|
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" : ""}`
|
|
3818
|
+
const rakeDbConfigDefaults = {
|
|
3819
|
+
...migrateConfigDefaults,
|
|
3820
|
+
schemaConfig: defaultSchemaConfig,
|
|
3821
|
+
snakeCase: false,
|
|
3822
|
+
commands: {},
|
|
3823
|
+
log: true,
|
|
3824
|
+
logger: console,
|
|
3825
|
+
import() {
|
|
3826
|
+
throw new Error(
|
|
3827
|
+
"Add `import: (path) => import(path),` setting to `rakeDb` config"
|
|
3944
3828
|
);
|
|
3945
3829
|
}
|
|
3946
3830
|
};
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
})
|
|
3831
|
+
|
|
3832
|
+
const ESC = "\x1B";
|
|
3833
|
+
const CSI = `${ESC}[`;
|
|
3834
|
+
const cursorShow = `${CSI}?25h`;
|
|
3835
|
+
const cursorHide = `${CSI}?25l`;
|
|
3836
|
+
const { stdin, stdout } = process;
|
|
3837
|
+
const visibleChars = (s) => s.replace(
|
|
3838
|
+
// eslint-disable-next-line no-control-regex
|
|
3839
|
+
/[\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,
|
|
3840
|
+
""
|
|
3841
|
+
).length;
|
|
3842
|
+
const clear = (text) => {
|
|
3843
|
+
const rows = text.split(/\r?\n/).reduce(
|
|
3844
|
+
(rows2, line) => rows2 + 1 + Math.floor(Math.max(visibleChars(line) - 1, 0) / stdout.columns),
|
|
3845
|
+
0
|
|
3963
3846
|
);
|
|
3847
|
+
let clear2 = "";
|
|
3848
|
+
for (let i = 0; i < rows; i++) {
|
|
3849
|
+
clear2 += `${CSI}2K`;
|
|
3850
|
+
if (i < rows - 1) {
|
|
3851
|
+
clear2 += `${CSI}${i < rows - 1 ? "1A" : "G"}`;
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
return clear2;
|
|
3964
3855
|
};
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3856
|
+
const prompt = async ({
|
|
3857
|
+
render,
|
|
3858
|
+
onKeyPress,
|
|
3859
|
+
validate,
|
|
3860
|
+
value,
|
|
3861
|
+
cursor: showCursor
|
|
3862
|
+
}) => {
|
|
3863
|
+
stdin.resume();
|
|
3864
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
3865
|
+
stdin.setEncoding("utf-8");
|
|
3866
|
+
if (!showCursor) stdout.write(cursorHide);
|
|
3867
|
+
return new Promise((res) => {
|
|
3868
|
+
let prevText;
|
|
3869
|
+
const ctx = {
|
|
3870
|
+
value,
|
|
3871
|
+
submitted: false,
|
|
3872
|
+
render() {
|
|
3873
|
+
let text = (ctx.submitted ? colors.greenBold("\u2714") : colors.yellowBold("?")) + " " + render(ctx);
|
|
3874
|
+
if (ctx.submitted) text += "\n";
|
|
3875
|
+
stdout.write(prevText ? clear(prevText) + "\r" + text : text);
|
|
3876
|
+
prevText = text;
|
|
3877
|
+
},
|
|
3878
|
+
submit(value2) {
|
|
3879
|
+
if (value2 !== void 0) ctx.value = value2;
|
|
3880
|
+
if (ctx.value === void 0 || validate && !validate?.(ctx)) return;
|
|
3881
|
+
ctx.submitted = true;
|
|
3882
|
+
ctx.render();
|
|
3883
|
+
close();
|
|
3884
|
+
res(ctx.value);
|
|
3985
3885
|
}
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
}
|
|
3998
|
-
await createMigrationsSchemaAndTable(tx, config);
|
|
3999
|
-
});
|
|
4000
|
-
if (!dontClose) {
|
|
4001
|
-
await adapter.close();
|
|
3886
|
+
};
|
|
3887
|
+
const close = () => {
|
|
3888
|
+
if (!showCursor) stdout.write(cursorShow);
|
|
3889
|
+
if (stdin.isTTY) stdin.setRawMode(false);
|
|
3890
|
+
stdin.off("data", keypress);
|
|
3891
|
+
stdin.pause();
|
|
3892
|
+
};
|
|
3893
|
+
const keypress = (s) => {
|
|
3894
|
+
if (s === "" || s === "") {
|
|
3895
|
+
close?.();
|
|
3896
|
+
process.exit(0);
|
|
4002
3897
|
}
|
|
4003
|
-
|
|
4004
|
-
|
|
3898
|
+
if (s === "\r" || s === "\n" || s === "\r\n") {
|
|
3899
|
+
ctx.submit();
|
|
3900
|
+
} else {
|
|
3901
|
+
onKeyPress(ctx, s);
|
|
3902
|
+
}
|
|
3903
|
+
};
|
|
3904
|
+
stdin.on("data", keypress);
|
|
3905
|
+
ctx.render();
|
|
3906
|
+
});
|
|
4005
3907
|
};
|
|
4006
|
-
const
|
|
3908
|
+
const defaultActive = (s) => `${colors.blueBold("\u276F")} ${s}`;
|
|
3909
|
+
const defaultInactive = (s) => ` ${s}`;
|
|
3910
|
+
const promptSelect = ({
|
|
3911
|
+
message,
|
|
3912
|
+
options,
|
|
3913
|
+
active = defaultActive,
|
|
3914
|
+
inactive = defaultInactive
|
|
3915
|
+
}) => prompt({
|
|
3916
|
+
value: 0,
|
|
3917
|
+
render(ctx) {
|
|
3918
|
+
let text = `${message} ${colors.pale(
|
|
3919
|
+
"Use arrows or jk. Press enter to submit."
|
|
3920
|
+
)}
|
|
3921
|
+
`;
|
|
3922
|
+
for (let i = 0; i < options.length; i++) {
|
|
3923
|
+
text += (ctx.value === i ? active : inactive)(options[i]) + "\n";
|
|
3924
|
+
}
|
|
3925
|
+
return text;
|
|
3926
|
+
},
|
|
3927
|
+
onKeyPress(ctx, s) {
|
|
3928
|
+
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;
|
|
3929
|
+
ctx.render();
|
|
3930
|
+
}
|
|
3931
|
+
});
|
|
3932
|
+
const promptConfirm = ({
|
|
3933
|
+
message
|
|
3934
|
+
}) => prompt({
|
|
3935
|
+
value: true,
|
|
3936
|
+
render(ctx) {
|
|
3937
|
+
return `${colors.bright(message)}
|
|
3938
|
+
${ctx.submitted ? `> ${ctx.value ? colors.greenBold("Yes") : colors.yellowBold("No")}` : colors.pale(`> (Y/n)`)}
|
|
3939
|
+
`;
|
|
3940
|
+
},
|
|
3941
|
+
onKeyPress(ctx, s) {
|
|
3942
|
+
let ok;
|
|
3943
|
+
if (s === "y" || s === "Y") ok = true;
|
|
3944
|
+
else if (s === "n" || s === "N") ok = false;
|
|
3945
|
+
if (ok !== void 0) {
|
|
3946
|
+
ctx.submit(ok);
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
});
|
|
3950
|
+
const promptText = ({
|
|
3951
|
+
message,
|
|
3952
|
+
default: def = "",
|
|
3953
|
+
password,
|
|
3954
|
+
min
|
|
3955
|
+
}) => {
|
|
3956
|
+
let showDefault = true;
|
|
3957
|
+
let x = 0;
|
|
3958
|
+
const renderValue = (ctx) => password ? "*".repeat(ctx.value.length) : ctx.value;
|
|
3959
|
+
return prompt({
|
|
3960
|
+
value: def,
|
|
3961
|
+
cursor: true,
|
|
3962
|
+
validate: (ctx) => !min || ctx.value.length >= min,
|
|
3963
|
+
render(ctx) {
|
|
3964
|
+
let text = `${colors.bright(message)}
|
|
3965
|
+
> ${ctx.submitted ? renderValue(ctx) : showDefault ? colors.pale(def) + "\b".repeat(def.length) : ctx.value}`;
|
|
3966
|
+
if (ctx.submitted) text += "\n";
|
|
3967
|
+
return text;
|
|
3968
|
+
},
|
|
3969
|
+
onKeyPress(ctx, s) {
|
|
3970
|
+
let value = showDefault ? "" : ctx.value;
|
|
3971
|
+
if (s === "\x1B[D" && x > 0) {
|
|
3972
|
+
x--;
|
|
3973
|
+
stdout.write("\b");
|
|
3974
|
+
} else if (s === "\x1B[C" && x < value.length) {
|
|
3975
|
+
stdout.write(value[x]);
|
|
3976
|
+
x++;
|
|
3977
|
+
}
|
|
3978
|
+
if (s !== "\x7F" && s !== "\x1B[3~" && !visibleChars(s)) return;
|
|
3979
|
+
if (showDefault) {
|
|
3980
|
+
showDefault = false;
|
|
3981
|
+
stdout.write(" ".repeat(def.length) + "\b".repeat(def.length));
|
|
3982
|
+
}
|
|
3983
|
+
const prev = value;
|
|
3984
|
+
const prevX = x;
|
|
3985
|
+
if (s === "\x7F") {
|
|
3986
|
+
if (x > 0) {
|
|
3987
|
+
value = value.slice(0, x - 1) + value.slice(x);
|
|
3988
|
+
x--;
|
|
3989
|
+
}
|
|
3990
|
+
} else if (s === "\x1B[3~") {
|
|
3991
|
+
if (x < value.length) {
|
|
3992
|
+
value = value.slice(0, x) + value.slice(x + 1);
|
|
3993
|
+
}
|
|
3994
|
+
} else {
|
|
3995
|
+
value = value.slice(0, x) + s + value.slice(x);
|
|
3996
|
+
x++;
|
|
3997
|
+
}
|
|
3998
|
+
ctx.value = value;
|
|
3999
|
+
const spaces = prev.length - value.length;
|
|
4000
|
+
stdout.write(
|
|
4001
|
+
"\b".repeat(prevX) + renderValue(ctx) + (spaces > 0 ? " ".repeat(spaces) + "\b".repeat(spaces) : "") + "\b".repeat(value.length - x)
|
|
4002
|
+
);
|
|
4003
|
+
}
|
|
4004
|
+
});
|
|
4005
|
+
};
|
|
4006
|
+
|
|
4007
|
+
const runRecurrentMigrations = async (adapters, config) => {
|
|
4008
|
+
let dbs;
|
|
4009
|
+
let files = 0;
|
|
4010
|
+
await readdirRecursive(config.recurrentPath, async (path) => {
|
|
4011
|
+
files++;
|
|
4012
|
+
dbs ?? (dbs = adapters.map((adapter) => createDbWithAdapter({ adapter })));
|
|
4013
|
+
const sql = await readFile(path, "utf-8");
|
|
4014
|
+
await Promise.all(
|
|
4015
|
+
dbs.map(async (db) => {
|
|
4016
|
+
await db.adapter.arrays(sql);
|
|
4017
|
+
})
|
|
4018
|
+
);
|
|
4019
|
+
});
|
|
4020
|
+
if (files > 0) {
|
|
4021
|
+
config.logger?.log(
|
|
4022
|
+
`Applied ${files} recurrent migration file${files > 1 ? "s" : ""}`
|
|
4023
|
+
);
|
|
4024
|
+
}
|
|
4025
|
+
};
|
|
4026
|
+
const readdirRecursive = async (dirPath, cb) => {
|
|
4027
|
+
const list = await readdir(dirPath).catch((err) => {
|
|
4028
|
+
if (err.code !== "ENOENT") throw err;
|
|
4029
|
+
return;
|
|
4030
|
+
});
|
|
4031
|
+
if (!list) return;
|
|
4032
|
+
await Promise.all(
|
|
4033
|
+
list.map(async (item) => {
|
|
4034
|
+
const path = join(dirPath, item);
|
|
4035
|
+
const info = await stat(path);
|
|
4036
|
+
if (info.isDirectory()) {
|
|
4037
|
+
await readdirRecursive(path, cb);
|
|
4038
|
+
} else if (info.isFile() && path.endsWith(".sql")) {
|
|
4039
|
+
await cb(path);
|
|
4040
|
+
}
|
|
4041
|
+
})
|
|
4042
|
+
);
|
|
4043
|
+
};
|
|
4044
|
+
|
|
4045
|
+
const createDatabaseCommand = (adapters, config, dontClose) => createOrDropDatabase("create", adapters, config, dontClose);
|
|
4046
|
+
const dropDatabaseCommand = (adapters, config) => createOrDropDatabase("drop", adapters, config);
|
|
4047
|
+
const createOrDropDatabase = async (action, adapters, config, dontClose) => {
|
|
4048
|
+
const fn = action === "create" ? createDatabase : dropDatabase;
|
|
4049
|
+
for (const adapter of adapters) {
|
|
4050
|
+
const database = adapter.getDatabase();
|
|
4051
|
+
const owner = adapter.getUser();
|
|
4052
|
+
const res = await run(
|
|
4053
|
+
adapter.reconfigure({ database: "postgres" }),
|
|
4054
|
+
config,
|
|
4055
|
+
{
|
|
4056
|
+
command: (adapter2) => fn(adapter2, {
|
|
4057
|
+
database,
|
|
4058
|
+
owner
|
|
4059
|
+
}),
|
|
4060
|
+
doneMessage: () => `Database ${database} successfully ${action === "create" ? "created" : "dropped"}`,
|
|
4061
|
+
alreadyMessage: () => `Database ${database} ${action === "create" ? "already exists" : "does not exist"}`,
|
|
4062
|
+
deniedMessage: () => `Permission denied to ${action} database.`,
|
|
4063
|
+
askAdminCreds: () => askForAdminCredentials(action === "create")
|
|
4064
|
+
}
|
|
4065
|
+
);
|
|
4066
|
+
if (!res) continue;
|
|
4067
|
+
if (action === "create") {
|
|
4068
|
+
await adapter.transaction(async (tx) => {
|
|
4069
|
+
const schema = tx.getSchema();
|
|
4070
|
+
if (schema) {
|
|
4071
|
+
const quoted = `"${typeof schema === "function" ? schema() : schema}"`;
|
|
4072
|
+
const res2 = await createSchema(tx, quoted);
|
|
4073
|
+
if (res2 === "done") {
|
|
4074
|
+
config.logger?.log(`Created schema ${quoted}`);
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
await createMigrationsSchemaAndTable(tx, config);
|
|
4078
|
+
});
|
|
4079
|
+
if (!dontClose) {
|
|
4080
|
+
await adapter.close();
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
}
|
|
4084
|
+
};
|
|
4085
|
+
const resetDatabaseCommand = async (adapters, config) => {
|
|
4007
4086
|
await createOrDropDatabase("drop", adapters, config);
|
|
4008
4087
|
await createOrDropDatabase("create", adapters, config, true);
|
|
4009
4088
|
for (const adapter of adapters) {
|
|
@@ -6083,174 +6162,62 @@ Append \`as\` method manually to ${count > 1 ? "these" : "this"} column${count >
|
|
|
6083
6162
|
config.logger?.log("Database pulled successfully");
|
|
6084
6163
|
};
|
|
6085
6164
|
|
|
6086
|
-
const
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
);
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6165
|
+
const listMigrationsStatuses = async (adapters, config, params) => {
|
|
6166
|
+
const ctx = {};
|
|
6167
|
+
const [{ migrations }, ...migrated] = await Promise.all([
|
|
6168
|
+
getMigrations(ctx, config, true),
|
|
6169
|
+
...adapters.map((adapter) => getMigratedVersionsMap(ctx, adapter, config))
|
|
6170
|
+
]);
|
|
6171
|
+
const map = {};
|
|
6172
|
+
let maxVersionLength = 12;
|
|
6173
|
+
let maxNameLength = 4;
|
|
6174
|
+
for (let i = 0; i < adapters.length; i++) {
|
|
6175
|
+
const list = migrated[i];
|
|
6176
|
+
const key = Object.entries(list.map).map(([version, up]) => `${version}${up ? "t" : "f"}`).join("");
|
|
6177
|
+
const database = adapters[i].getDatabase();
|
|
6178
|
+
if (map[key]) {
|
|
6179
|
+
map[key].databases.push(database);
|
|
6180
|
+
continue;
|
|
6181
|
+
}
|
|
6182
|
+
map[key] = {
|
|
6183
|
+
databases: [database],
|
|
6184
|
+
migrations: migrations.map((item) => {
|
|
6185
|
+
if (item.version.length > maxVersionLength) {
|
|
6186
|
+
maxVersionLength = item.version.length;
|
|
6187
|
+
}
|
|
6188
|
+
const name = path.parse(item.path).name.slice(item.version.length + 1).replace(
|
|
6189
|
+
/([a-z])([A-Z])/g,
|
|
6190
|
+
(_, a, b) => `${a} ${b.toLocaleLowerCase()}`
|
|
6191
|
+
).replace(/[-_](.)/g, (_, char) => ` ${char.toLocaleLowerCase()}`).replace(/^\w/, (match) => match.toLocaleUpperCase());
|
|
6192
|
+
if (name.length > maxNameLength) {
|
|
6193
|
+
maxNameLength = name.length;
|
|
6194
|
+
}
|
|
6195
|
+
return {
|
|
6196
|
+
up: !!list.map[item.version],
|
|
6197
|
+
version: item.version,
|
|
6198
|
+
name,
|
|
6199
|
+
url: pathToFileURL(item.path)
|
|
6200
|
+
};
|
|
6201
|
+
})
|
|
6202
|
+
};
|
|
6110
6203
|
}
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
const
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
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
|
-
);
|
|
6180
|
-
}
|
|
6181
|
-
result.transaction = transaction;
|
|
6182
|
-
} else if (!result.transaction) {
|
|
6183
|
-
result.transaction = "single";
|
|
6184
|
-
}
|
|
6185
|
-
let c = rakeDbCommands;
|
|
6186
|
-
if (config.commands) {
|
|
6187
|
-
c = { ...c };
|
|
6188
|
-
const commands = config.commands;
|
|
6189
|
-
for (const key in commands) {
|
|
6190
|
-
const command = commands[key];
|
|
6191
|
-
c[key] = typeof command === "function" ? { run: command } : command;
|
|
6192
|
-
}
|
|
6193
|
-
}
|
|
6194
|
-
result.commands = c;
|
|
6195
|
-
return result;
|
|
6196
|
-
};
|
|
6197
|
-
|
|
6198
|
-
const listMigrationsStatuses = async (adapters, config, params) => {
|
|
6199
|
-
const ctx = {};
|
|
6200
|
-
const [{ migrations }, ...migrated] = await Promise.all([
|
|
6201
|
-
getMigrations(ctx, config, true),
|
|
6202
|
-
...adapters.map((adapter) => getMigratedVersionsMap(ctx, adapter, config))
|
|
6203
|
-
]);
|
|
6204
|
-
const map = {};
|
|
6205
|
-
let maxVersionLength = 12;
|
|
6206
|
-
let maxNameLength = 4;
|
|
6207
|
-
for (let i = 0; i < adapters.length; i++) {
|
|
6208
|
-
const list = migrated[i];
|
|
6209
|
-
const key = Object.entries(list.map).map(([version, up]) => `${version}${up ? "t" : "f"}`).join("");
|
|
6210
|
-
const database = adapters[i].getDatabase();
|
|
6211
|
-
if (map[key]) {
|
|
6212
|
-
map[key].databases.push(database);
|
|
6213
|
-
continue;
|
|
6214
|
-
}
|
|
6215
|
-
map[key] = {
|
|
6216
|
-
databases: [database],
|
|
6217
|
-
migrations: migrations.map((item) => {
|
|
6218
|
-
if (item.version.length > maxVersionLength) {
|
|
6219
|
-
maxVersionLength = item.version.length;
|
|
6220
|
-
}
|
|
6221
|
-
const name = path.parse(item.path).name.slice(item.version.length + 1).replace(
|
|
6222
|
-
/([a-z])([A-Z])/g,
|
|
6223
|
-
(_, a, b) => `${a} ${b.toLocaleLowerCase()}`
|
|
6224
|
-
).replace(/[-_](.)/g, (_, char) => ` ${char.toLocaleLowerCase()}`).replace(/^\w/, (match) => match.toLocaleUpperCase());
|
|
6225
|
-
if (name.length > maxNameLength) {
|
|
6226
|
-
maxNameLength = name.length;
|
|
6227
|
-
}
|
|
6228
|
-
return {
|
|
6229
|
-
up: !!list.map[item.version],
|
|
6230
|
-
version: item.version,
|
|
6231
|
-
name,
|
|
6232
|
-
url: pathToFileURL(item.path)
|
|
6233
|
-
};
|
|
6234
|
-
})
|
|
6235
|
-
};
|
|
6236
|
-
}
|
|
6237
|
-
const showUrl = params?.showUrl;
|
|
6238
|
-
const asIs = (s) => s;
|
|
6239
|
-
const c = typeof config.log === "object" && config.log.colors === false ? {
|
|
6240
|
-
yellow: asIs,
|
|
6241
|
-
green: asIs,
|
|
6242
|
-
red: asIs,
|
|
6243
|
-
blue: asIs
|
|
6244
|
-
} : colors;
|
|
6245
|
-
const log = Object.values(map).map(({ databases, migrations: migrations2 }) => {
|
|
6246
|
-
let log2 = ` ${c.yellow("Database:")} ${databases.join(", ")}`;
|
|
6247
|
-
if (migrations2.length === 0) {
|
|
6248
|
-
return log2 + `
|
|
6249
|
-
|
|
6250
|
-
No migrations available`;
|
|
6251
|
-
}
|
|
6252
|
-
const lineSeparator = c.yellow(
|
|
6253
|
-
makeChars(14 + maxVersionLength + maxNameLength, "-")
|
|
6204
|
+
const showUrl = params?.showUrl;
|
|
6205
|
+
const asIs = (s) => s;
|
|
6206
|
+
const c = typeof config.log === "object" && config.log.colors === false ? {
|
|
6207
|
+
yellow: asIs,
|
|
6208
|
+
green: asIs,
|
|
6209
|
+
red: asIs,
|
|
6210
|
+
blue: asIs
|
|
6211
|
+
} : colors;
|
|
6212
|
+
const log = Object.values(map).map(({ databases, migrations: migrations2 }) => {
|
|
6213
|
+
let log2 = ` ${c.yellow("Database:")} ${databases.join(", ")}`;
|
|
6214
|
+
if (migrations2.length === 0) {
|
|
6215
|
+
return log2 + `
|
|
6216
|
+
|
|
6217
|
+
No migrations available`;
|
|
6218
|
+
}
|
|
6219
|
+
const lineSeparator = c.yellow(
|
|
6220
|
+
makeChars(14 + maxVersionLength + maxNameLength, "-")
|
|
6254
6221
|
);
|
|
6255
6222
|
const columnSeparator = c.yellow("|");
|
|
6256
6223
|
log2 += "\n\n " + c.yellow(
|
|
@@ -6439,6 +6406,196 @@ const rebase = async (adapters, config) => {
|
|
|
6439
6406
|
}
|
|
6440
6407
|
};
|
|
6441
6408
|
|
|
6409
|
+
const close = (adapters) => Promise.all(adapters.map((adapter) => adapter.close()));
|
|
6410
|
+
const maybeRunRecurrent = async (adapters, config) => {
|
|
6411
|
+
config.recurrentPath && await runRecurrentMigrations(
|
|
6412
|
+
adapters,
|
|
6413
|
+
config
|
|
6414
|
+
);
|
|
6415
|
+
};
|
|
6416
|
+
const rakeDbAliases$1 = {
|
|
6417
|
+
migrate: "up",
|
|
6418
|
+
rollback: "down",
|
|
6419
|
+
s: "status",
|
|
6420
|
+
rec: "recurrent"
|
|
6421
|
+
};
|
|
6422
|
+
const upCommand = {
|
|
6423
|
+
run: (adapters, config, args) => migrateCommand(adapters, config, args).then(() => maybeRunRecurrent(adapters, config)).then(() => close(adapters)),
|
|
6424
|
+
help: "migrate pending migrations",
|
|
6425
|
+
helpArguments: {
|
|
6426
|
+
"no arguments": "migrate all pending",
|
|
6427
|
+
"a number": "run a specific number of pending migrations",
|
|
6428
|
+
force: "enforce migrating a pending file in the middle"
|
|
6429
|
+
}
|
|
6430
|
+
};
|
|
6431
|
+
const downCommand = {
|
|
6432
|
+
run: (adapters, config, args) => rollbackCommand(adapters, config, args).then(() => close(adapters)),
|
|
6433
|
+
help: "rollback migrated migrations",
|
|
6434
|
+
helpArguments: {
|
|
6435
|
+
"no arguments": "rollback one last migration",
|
|
6436
|
+
"a number": "rollback a specified number",
|
|
6437
|
+
all: "rollback all migrations"
|
|
6438
|
+
}
|
|
6439
|
+
};
|
|
6440
|
+
const statusCommand = {
|
|
6441
|
+
run(adapters, config, args) {
|
|
6442
|
+
const showUrl = args.includes("p") || args.includes("path");
|
|
6443
|
+
return listMigrationsStatuses(adapters, config, { showUrl });
|
|
6444
|
+
},
|
|
6445
|
+
help: "list migrations statuses",
|
|
6446
|
+
helpArguments: {
|
|
6447
|
+
"no arguments": `does not print file paths`,
|
|
6448
|
+
"p, path": "also print file paths"
|
|
6449
|
+
}
|
|
6450
|
+
};
|
|
6451
|
+
const recurrent = {
|
|
6452
|
+
async run(adapters, config) {
|
|
6453
|
+
if (!config.recurrentPath) return;
|
|
6454
|
+
await maybeRunRecurrent(adapters, config).then(() => close(adapters));
|
|
6455
|
+
},
|
|
6456
|
+
help: "run recurrent migrations"
|
|
6457
|
+
};
|
|
6458
|
+
const rakeDbCommands = {
|
|
6459
|
+
create: {
|
|
6460
|
+
run: (adapters, config) => createDatabaseCommand(adapters, config),
|
|
6461
|
+
help: "create databases"
|
|
6462
|
+
},
|
|
6463
|
+
drop: {
|
|
6464
|
+
run: dropDatabaseCommand,
|
|
6465
|
+
help: "drop databases"
|
|
6466
|
+
},
|
|
6467
|
+
reset: {
|
|
6468
|
+
run: (adapters, config) => resetDatabaseCommand(adapters, config),
|
|
6469
|
+
help: "drop, create and migrate databases"
|
|
6470
|
+
},
|
|
6471
|
+
up: upCommand,
|
|
6472
|
+
down: downCommand,
|
|
6473
|
+
redo: {
|
|
6474
|
+
run: (adapters, config, args) => redoCommand(adapters, config, args).then(() => maybeRunRecurrent(adapters, config)).then(() => close(adapters)),
|
|
6475
|
+
help: "rollback and migrate, run recurrent"
|
|
6476
|
+
},
|
|
6477
|
+
pull: {
|
|
6478
|
+
run: ([adapter], config) => pullDbStructure(adapter, config).then(() => close([adapter])),
|
|
6479
|
+
help: "generate a combined migration for an existing database"
|
|
6480
|
+
},
|
|
6481
|
+
new: {
|
|
6482
|
+
run(_, config, args) {
|
|
6483
|
+
const [name] = args;
|
|
6484
|
+
if (!name) throw new Error("Migration name is missing");
|
|
6485
|
+
return newMigration(config, name);
|
|
6486
|
+
},
|
|
6487
|
+
help: "create new migration file"
|
|
6488
|
+
},
|
|
6489
|
+
status: statusCommand,
|
|
6490
|
+
recurrent,
|
|
6491
|
+
rebase: {
|
|
6492
|
+
run: (adapters, config) => rebase(adapters, config).then(() => close(adapters)),
|
|
6493
|
+
help: "move local migrations below the new ones from upstream"
|
|
6494
|
+
},
|
|
6495
|
+
"change-ids": {
|
|
6496
|
+
run(adapters, config, [format, digitsArg]) {
|
|
6497
|
+
if (format !== "serial" && format !== "timestamp") {
|
|
6498
|
+
throw new Error(
|
|
6499
|
+
`Pass "serial" or "timestamp" argument to the "change-ids" command`
|
|
6500
|
+
);
|
|
6501
|
+
}
|
|
6502
|
+
const digits = digitsArg ? parseInt(digitsArg) : void 0;
|
|
6503
|
+
if (digits && isNaN(digits)) {
|
|
6504
|
+
throw new Error(`Second argument is optional and must be an integer`);
|
|
6505
|
+
}
|
|
6506
|
+
return changeIds(adapters, config, { format, digits });
|
|
6507
|
+
},
|
|
6508
|
+
help: "change migrations ids format",
|
|
6509
|
+
helpArguments: {
|
|
6510
|
+
serial: "change ids to 4 digit serial",
|
|
6511
|
+
"serial *number*": "change ids to serial number of custom length",
|
|
6512
|
+
timestamp: "change timestamps"
|
|
6513
|
+
}
|
|
6514
|
+
}
|
|
6515
|
+
};
|
|
6516
|
+
for (const key in rakeDbAliases$1) {
|
|
6517
|
+
const command = rakeDbAliases$1[key];
|
|
6518
|
+
if (command) rakeDbCommands[key] = rakeDbCommands[command];
|
|
6519
|
+
}
|
|
6520
|
+
let intermediateCallers = 0;
|
|
6521
|
+
const incrementIntermediateCaller = () => {
|
|
6522
|
+
intermediateCallers++;
|
|
6523
|
+
};
|
|
6524
|
+
const ensureBasePathAndDbScript = (config, intermediateCallers2 = 0) => {
|
|
6525
|
+
if (config.basePath && config.dbScript) return config;
|
|
6526
|
+
let filePath = getStackTrace()?.[3 + intermediateCallers2]?.getFileName();
|
|
6527
|
+
if (!filePath) {
|
|
6528
|
+
throw new Error(
|
|
6529
|
+
"Failed to determine path to db script. Please set basePath option of rakeDb"
|
|
6530
|
+
);
|
|
6531
|
+
}
|
|
6532
|
+
if (filePath.startsWith("file://")) {
|
|
6533
|
+
filePath = fileURLToPath(filePath);
|
|
6534
|
+
}
|
|
6535
|
+
const ext = path.extname(filePath);
|
|
6536
|
+
if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
|
|
6537
|
+
throw new Error(
|
|
6538
|
+
`Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
|
|
6539
|
+
);
|
|
6540
|
+
}
|
|
6541
|
+
config.basePath = path.dirname(filePath);
|
|
6542
|
+
config.dbScript = path.basename(filePath);
|
|
6543
|
+
return config;
|
|
6544
|
+
};
|
|
6545
|
+
const makeRakeDbConfig = (config, args) => {
|
|
6546
|
+
const ic = intermediateCallers;
|
|
6547
|
+
intermediateCallers = 0;
|
|
6548
|
+
const result = {
|
|
6549
|
+
...rakeDbConfigDefaults,
|
|
6550
|
+
...config,
|
|
6551
|
+
__rakeDbConfig: true
|
|
6552
|
+
};
|
|
6553
|
+
ensureBasePathAndDbScript(result, ic);
|
|
6554
|
+
Object.assign(result, processMigrateConfig(result));
|
|
6555
|
+
if (!result.recurrentPath && result.migrationsPath) {
|
|
6556
|
+
result.recurrentPath = path.join(result.migrationsPath, "recurrent");
|
|
6557
|
+
}
|
|
6558
|
+
if (result.recurrentPath && !path.isAbsolute(result.recurrentPath)) {
|
|
6559
|
+
result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
|
|
6560
|
+
}
|
|
6561
|
+
if ("baseTable" in config && config.baseTable) {
|
|
6562
|
+
const { types, snakeCase, language } = config.baseTable.prototype;
|
|
6563
|
+
result.columnTypes = types || makeColumnTypes(defaultSchemaConfig);
|
|
6564
|
+
if (snakeCase) result.snakeCase = true;
|
|
6565
|
+
if (language) result.language = language;
|
|
6566
|
+
} else {
|
|
6567
|
+
const ct = "columnTypes" in config && config.columnTypes;
|
|
6568
|
+
result.columnTypes = (typeof ct === "function" ? ct(
|
|
6569
|
+
makeColumnTypes(defaultSchemaConfig)
|
|
6570
|
+
) : ct) || makeColumnTypes(defaultSchemaConfig);
|
|
6571
|
+
}
|
|
6572
|
+
if (config.migrationId === "serial") {
|
|
6573
|
+
result.migrationId = { serial: 4 };
|
|
6574
|
+
}
|
|
6575
|
+
const transaction = getCliParam(args, "transaction");
|
|
6576
|
+
if (transaction) {
|
|
6577
|
+
if (transaction !== "single" && transaction !== "per-migration") {
|
|
6578
|
+
throw new Error(
|
|
6579
|
+
`Unsupported transaction param ${transaction}, expected single or per-migration`
|
|
6580
|
+
);
|
|
6581
|
+
}
|
|
6582
|
+
result.transaction = transaction;
|
|
6583
|
+
} else if (!result.transaction) {
|
|
6584
|
+
result.transaction = "single";
|
|
6585
|
+
}
|
|
6586
|
+
let c = rakeDbCommands;
|
|
6587
|
+
if (config.commands) {
|
|
6588
|
+
c = { ...c };
|
|
6589
|
+
const commands = config.commands;
|
|
6590
|
+
for (const key in commands) {
|
|
6591
|
+
const command = commands[key];
|
|
6592
|
+
c[key] = typeof command === "function" ? { run: command } : command;
|
|
6593
|
+
}
|
|
6594
|
+
}
|
|
6595
|
+
result.commands = c;
|
|
6596
|
+
return result;
|
|
6597
|
+
};
|
|
6598
|
+
|
|
6442
6599
|
const rakeDbAliases = {
|
|
6443
6600
|
migrate: "up",
|
|
6444
6601
|
rollback: "down",
|
|
@@ -6454,7 +6611,7 @@ const rakeDbCliWithAdapter = (inputConfig, args = process.argv.slice(2)) => {
|
|
|
6454
6611
|
config = makeRakeDbConfig(inputConfig, args);
|
|
6455
6612
|
}
|
|
6456
6613
|
return {
|
|
6457
|
-
change:
|
|
6614
|
+
change: createMigrationChangeFn(config),
|
|
6458
6615
|
async run(adapter, runArgs) {
|
|
6459
6616
|
const adapters = toArray(adapter);
|
|
6460
6617
|
try {
|
|
@@ -6548,111 +6705,6 @@ ${Object.entries(helpArguments).map(
|
|
|
6548
6705
|
`);
|
|
6549
6706
|
}
|
|
6550
6707
|
};
|
|
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
6708
|
|
|
6657
|
-
export { RakeDbError, astToMigration, concatSchemaAndName, createDatabase, createMigrationInterface, createMigrationsSchemaAndTable, createSchema
|
|
6709
|
+
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
6710
|
//# sourceMappingURL=index.mjs.map
|