rake-db 2.28.1 → 2.29.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 +281 -308
- package/dist/index.js +978 -826
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +974 -823
- package/dist/index.mjs.map +1 -1
- package/dist/node-postgres.d.ts +2 -6
- package/dist/node-postgres.js +10 -36
- package/dist/node-postgres.js.map +1 -1
- package/dist/node-postgres.mjs +11 -36
- package/dist/node-postgres.mjs.map +1 -1
- package/dist/postgres-js.d.ts +3 -7
- package/dist/postgres-js.js +10 -36
- package/dist/postgres-js.js.map +1 -1
- package/dist/postgres-js.mjs +11 -36
- package/dist/postgres-js.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5,17 +5,248 @@ var path = require('path');
|
|
|
5
5
|
var node_url = require('node:url');
|
|
6
6
|
var fs = require('fs/promises');
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
}
|
|
8
|
+
const ESC = "\x1B";
|
|
9
|
+
const CSI = `${ESC}[`;
|
|
10
|
+
const cursorShow = `${CSI}?25h`;
|
|
11
|
+
const cursorHide = `${CSI}?25l`;
|
|
12
|
+
const { stdin, stdout } = process;
|
|
13
|
+
const visibleChars = (s) => s.replace(
|
|
14
|
+
// eslint-disable-next-line no-control-regex
|
|
15
|
+
/[\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,
|
|
16
|
+
""
|
|
17
|
+
).length;
|
|
18
|
+
const clear = (text) => {
|
|
19
|
+
const rows = text.split(/\r?\n/).reduce(
|
|
20
|
+
(rows2, line) => rows2 + 1 + Math.floor(Math.max(visibleChars(line) - 1, 0) / stdout.columns),
|
|
21
|
+
0
|
|
22
|
+
);
|
|
23
|
+
let clear2 = "";
|
|
24
|
+
for (let i = 0; i < rows; i++) {
|
|
25
|
+
clear2 += `${CSI}2K`;
|
|
26
|
+
if (i < rows - 1) {
|
|
27
|
+
clear2 += `${CSI}${i < rows - 1 ? "1A" : "G"}`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return clear2;
|
|
31
|
+
};
|
|
32
|
+
const prompt = async ({
|
|
33
|
+
render,
|
|
34
|
+
onKeyPress,
|
|
35
|
+
validate,
|
|
36
|
+
value,
|
|
37
|
+
cursor: showCursor
|
|
38
|
+
}) => {
|
|
39
|
+
stdin.resume();
|
|
40
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
41
|
+
stdin.setEncoding("utf-8");
|
|
42
|
+
if (!showCursor) stdout.write(cursorHide);
|
|
43
|
+
return new Promise((res) => {
|
|
44
|
+
let prevText;
|
|
45
|
+
const ctx = {
|
|
46
|
+
value,
|
|
47
|
+
submitted: false,
|
|
48
|
+
render() {
|
|
49
|
+
let text = (ctx.submitted ? pqb.colors.greenBold("\u2714") : pqb.colors.yellowBold("?")) + " " + render(ctx);
|
|
50
|
+
if (ctx.submitted) text += "\n";
|
|
51
|
+
stdout.write(prevText ? clear(prevText) + "\r" + text : text);
|
|
52
|
+
prevText = text;
|
|
53
|
+
},
|
|
54
|
+
submit(value2) {
|
|
55
|
+
if (value2 !== void 0) ctx.value = value2;
|
|
56
|
+
if (ctx.value === void 0 || validate && !validate?.(ctx)) return;
|
|
57
|
+
ctx.submitted = true;
|
|
58
|
+
ctx.render();
|
|
59
|
+
close();
|
|
60
|
+
res(ctx.value);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const close = () => {
|
|
64
|
+
if (!showCursor) stdout.write(cursorShow);
|
|
65
|
+
if (stdin.isTTY) stdin.setRawMode(false);
|
|
66
|
+
stdin.off("data", keypress);
|
|
67
|
+
stdin.pause();
|
|
68
|
+
};
|
|
69
|
+
const keypress = (s) => {
|
|
70
|
+
if (s === "" || s === "") {
|
|
71
|
+
close?.();
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
if (s === "\r" || s === "\n" || s === "\r\n") {
|
|
75
|
+
ctx.submit();
|
|
76
|
+
} else {
|
|
77
|
+
onKeyPress(ctx, s);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
stdin.on("data", keypress);
|
|
81
|
+
ctx.render();
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
const defaultActive = (s) => `${pqb.colors.blueBold("\u276F")} ${s}`;
|
|
85
|
+
const defaultInactive = (s) => ` ${s}`;
|
|
86
|
+
const promptSelect = ({
|
|
87
|
+
message,
|
|
88
|
+
options,
|
|
89
|
+
active = defaultActive,
|
|
90
|
+
inactive = defaultInactive
|
|
91
|
+
}) => prompt({
|
|
92
|
+
value: 0,
|
|
93
|
+
render(ctx) {
|
|
94
|
+
let text = `${message} ${pqb.colors.pale(
|
|
95
|
+
"Use arrows or jk. Press enter to submit."
|
|
96
|
+
)}
|
|
97
|
+
`;
|
|
98
|
+
for (let i = 0; i < options.length; i++) {
|
|
99
|
+
text += (ctx.value === i ? active : inactive)(options[i]) + "\n";
|
|
100
|
+
}
|
|
101
|
+
return text;
|
|
102
|
+
},
|
|
103
|
+
onKeyPress(ctx, s) {
|
|
104
|
+
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;
|
|
105
|
+
ctx.render();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
const promptConfirm = ({
|
|
109
|
+
message
|
|
110
|
+
}) => prompt({
|
|
111
|
+
value: true,
|
|
112
|
+
render(ctx) {
|
|
113
|
+
return `${pqb.colors.bright(message)}
|
|
114
|
+
${ctx.submitted ? `> ${ctx.value ? pqb.colors.greenBold("Yes") : pqb.colors.yellowBold("No")}` : pqb.colors.pale(`> (Y/n)`)}
|
|
115
|
+
`;
|
|
116
|
+
},
|
|
117
|
+
onKeyPress(ctx, s) {
|
|
118
|
+
let ok;
|
|
119
|
+
if (s === "y" || s === "Y") ok = true;
|
|
120
|
+
else if (s === "n" || s === "N") ok = false;
|
|
121
|
+
if (ok !== void 0) {
|
|
122
|
+
ctx.submit(ok);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
const promptText = ({
|
|
127
|
+
message,
|
|
128
|
+
default: def = "",
|
|
129
|
+
password,
|
|
130
|
+
min
|
|
131
|
+
}) => {
|
|
132
|
+
let showDefault = true;
|
|
133
|
+
let x = 0;
|
|
134
|
+
const renderValue = (ctx) => password ? "*".repeat(ctx.value.length) : ctx.value;
|
|
135
|
+
return prompt({
|
|
136
|
+
value: def,
|
|
137
|
+
cursor: true,
|
|
138
|
+
validate: (ctx) => !min || ctx.value.length >= min,
|
|
139
|
+
render(ctx) {
|
|
140
|
+
let text = `${pqb.colors.bright(message)}
|
|
141
|
+
> ${ctx.submitted ? renderValue(ctx) : showDefault ? pqb.colors.pale(def) + "\b".repeat(def.length) : ctx.value}`;
|
|
142
|
+
if (ctx.submitted) text += "\n";
|
|
143
|
+
return text;
|
|
144
|
+
},
|
|
145
|
+
onKeyPress(ctx, s) {
|
|
146
|
+
let value = showDefault ? "" : ctx.value;
|
|
147
|
+
if (s === "\x1B[D" && x > 0) {
|
|
148
|
+
x--;
|
|
149
|
+
stdout.write("\b");
|
|
150
|
+
} else if (s === "\x1B[C" && x < value.length) {
|
|
151
|
+
stdout.write(value[x]);
|
|
152
|
+
x++;
|
|
153
|
+
}
|
|
154
|
+
if (s !== "\x7F" && s !== "\x1B[3~" && !visibleChars(s)) return;
|
|
155
|
+
if (showDefault) {
|
|
156
|
+
showDefault = false;
|
|
157
|
+
stdout.write(" ".repeat(def.length) + "\b".repeat(def.length));
|
|
158
|
+
}
|
|
159
|
+
const prev = value;
|
|
160
|
+
const prevX = x;
|
|
161
|
+
if (s === "\x7F") {
|
|
162
|
+
if (x > 0) {
|
|
163
|
+
value = value.slice(0, x - 1) + value.slice(x);
|
|
164
|
+
x--;
|
|
165
|
+
}
|
|
166
|
+
} else if (s === "\x1B[3~") {
|
|
167
|
+
if (x < value.length) {
|
|
168
|
+
value = value.slice(0, x) + value.slice(x + 1);
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
value = value.slice(0, x) + s + value.slice(x);
|
|
172
|
+
x++;
|
|
173
|
+
}
|
|
174
|
+
ctx.value = value;
|
|
175
|
+
const spaces = prev.length - value.length;
|
|
176
|
+
stdout.write(
|
|
177
|
+
"\b".repeat(prevX) + renderValue(ctx) + (spaces > 0 ? " ".repeat(spaces) + "\b".repeat(spaces) : "") + "\b".repeat(value.length - x)
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
};
|
|
12
182
|
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
183
|
+
const getNonTransactionAdapter = (db) => "$adapter" in db ? db.$adapter : db;
|
|
184
|
+
const getMaybeTransactionAdapter = (db) => "$qb" in db ? db.$qb.internal.transactionStorage.getStore()?.adapter || db.$adapter : db;
|
|
185
|
+
const ensureTransaction = (db, fn) => {
|
|
186
|
+
const adapter = getMaybeTransactionAdapter(db);
|
|
187
|
+
return adapter.isInTransaction() ? fn(adapter) : adapter.transaction(void 0, fn);
|
|
188
|
+
};
|
|
189
|
+
const runSqlInSavePoint = async (db, sql, code) => {
|
|
190
|
+
const adapter = getMaybeTransactionAdapter(db);
|
|
191
|
+
try {
|
|
192
|
+
await adapter.query(
|
|
193
|
+
adapter.isInTransaction() ? `SAVEPOINT s; ${sql}; RELEASE SAVEPOINT s` : sql
|
|
194
|
+
);
|
|
195
|
+
return "done";
|
|
196
|
+
} catch (err) {
|
|
197
|
+
if (err.code === code) {
|
|
198
|
+
if (adapter.isInTransaction()) {
|
|
199
|
+
await adapter.query(`ROLLBACK TO SAVEPOINT s`);
|
|
200
|
+
}
|
|
201
|
+
return "already";
|
|
202
|
+
}
|
|
203
|
+
throw err;
|
|
204
|
+
}
|
|
16
205
|
};
|
|
17
|
-
|
|
18
|
-
|
|
206
|
+
|
|
207
|
+
class CreateOrDropError extends Error {
|
|
208
|
+
constructor(message, status, cause) {
|
|
209
|
+
super(message);
|
|
210
|
+
this.status = status;
|
|
211
|
+
this.cause = cause;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const createDatabase = async (db, {
|
|
215
|
+
database,
|
|
216
|
+
owner
|
|
217
|
+
}) => {
|
|
218
|
+
return createOrDrop(
|
|
219
|
+
db,
|
|
220
|
+
`CREATE DATABASE "${database}"${owner ? ` OWNER "${owner}"` : ""}`
|
|
221
|
+
);
|
|
222
|
+
};
|
|
223
|
+
const dropDatabase = async (db, { database }) => {
|
|
224
|
+
return createOrDrop(db, `DROP DATABASE "${database}"`);
|
|
225
|
+
};
|
|
226
|
+
const createOrDrop = async (db, sql) => {
|
|
227
|
+
try {
|
|
228
|
+
const adapter = getNonTransactionAdapter(db);
|
|
229
|
+
await adapter.query(sql);
|
|
230
|
+
return "done";
|
|
231
|
+
} catch (error) {
|
|
232
|
+
const err = error;
|
|
233
|
+
if (typeof err.message === "string" && err.message.includes("sslmode=require")) {
|
|
234
|
+
throw new CreateOrDropError("SSL required", "ssl-required", err);
|
|
235
|
+
}
|
|
236
|
+
if (err.code === "42P04" || err.code === "3D000") {
|
|
237
|
+
return "already";
|
|
238
|
+
}
|
|
239
|
+
if (err.code === "42501") {
|
|
240
|
+
throw new CreateOrDropError("Insufficient privilege", "forbidden", err);
|
|
241
|
+
}
|
|
242
|
+
if (typeof err.message === "string" && err.message.includes("password authentication failed")) {
|
|
243
|
+
throw new CreateOrDropError("Authentication failed", "auth-failed", err);
|
|
244
|
+
}
|
|
245
|
+
throw err;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
const createSchema$1 = async (db, sql) => runSqlInSavePoint(db, `CREATE SCHEMA ${sql}`, "42P06");
|
|
249
|
+
const createTable$1 = async (db, sql) => runSqlInSavePoint(db, `CREATE TABLE ${sql}`, "42P07");
|
|
19
250
|
|
|
20
251
|
const RAKE_DB_LOCK_KEY = "8582141715823621641";
|
|
21
252
|
const getFirstWordAndRest = (input) => {
|
|
@@ -51,15 +282,18 @@ const quoteWithSchema = ({
|
|
|
51
282
|
name
|
|
52
283
|
}) => quoteTable(schema, name);
|
|
53
284
|
const quoteTable = (schema, table) => schema ? `"${schema}"."${table}"` : `"${table}"`;
|
|
54
|
-
const getSchemaAndTableFromName = (name) => {
|
|
285
|
+
const getSchemaAndTableFromName = (config, name) => {
|
|
55
286
|
const i = name.indexOf(".");
|
|
56
|
-
return i !== -1 ? [name.slice(0, i), name.slice(i + 1)] : [
|
|
287
|
+
return i !== -1 ? [name.slice(0, i), name.slice(i + 1)] : [
|
|
288
|
+
typeof config.schema === "function" ? config.schema() : config.schema,
|
|
289
|
+
name
|
|
290
|
+
];
|
|
57
291
|
};
|
|
58
|
-
const quoteNameFromString = (string) => {
|
|
59
|
-
return quoteTable(...getSchemaAndTableFromName(string));
|
|
292
|
+
const quoteNameFromString = (config, string) => {
|
|
293
|
+
return quoteTable(...getSchemaAndTableFromName(config, string));
|
|
60
294
|
};
|
|
61
|
-
const quoteCustomType = (s) => {
|
|
62
|
-
const [schema, type] = getSchemaAndTableFromName(s);
|
|
295
|
+
const quoteCustomType = (config, s) => {
|
|
296
|
+
const [schema, type] = getSchemaAndTableFromName(config, s);
|
|
63
297
|
return schema ? '"' + schema + '".' + type : type;
|
|
64
298
|
};
|
|
65
299
|
const quoteSchemaTable = (arg, excludeCurrentSchema) => {
|
|
@@ -71,8 +305,8 @@ const concatSchemaAndName = ({
|
|
|
71
305
|
}, excludeCurrentSchema) => {
|
|
72
306
|
return schema && schema !== excludeCurrentSchema ? `${schema}.${name}` : name;
|
|
73
307
|
};
|
|
74
|
-
const makePopulateEnumQuery = (item) => {
|
|
75
|
-
const [schema, name] = getSchemaAndTableFromName(item.enumName);
|
|
308
|
+
const makePopulateEnumQuery = (config, item) => {
|
|
309
|
+
const [schema, name] = getSchemaAndTableFromName(config, item.enumName);
|
|
76
310
|
return {
|
|
77
311
|
text: `SELECT unnest(enum_range(NULL::${quoteTable(schema, name)}))::text`,
|
|
78
312
|
then(result) {
|
|
@@ -96,115 +330,35 @@ const getCliParam = (args, name) => {
|
|
|
96
330
|
return;
|
|
97
331
|
};
|
|
98
332
|
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
migrationsTable: "schemaMigrations",
|
|
104
|
-
snakeCase: false,
|
|
105
|
-
commands: {},
|
|
106
|
-
log: true,
|
|
107
|
-
logger: console,
|
|
108
|
-
import() {
|
|
109
|
-
throw new Error(
|
|
110
|
-
"Add `import: (path) => import(path),` setting to `rakeDb` config"
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
const ensureMigrationsPath = (config) => {
|
|
115
|
-
if (!config.migrationsPath) {
|
|
116
|
-
config.migrationsPath = migrationConfigDefaults.migrationsPath;
|
|
117
|
-
}
|
|
118
|
-
if (!path.isAbsolute(config.migrationsPath)) {
|
|
119
|
-
config.migrationsPath = path.resolve(
|
|
120
|
-
config.basePath,
|
|
121
|
-
config.migrationsPath
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
return config;
|
|
125
|
-
};
|
|
126
|
-
const ensureBasePathAndDbScript = (config, intermediateCallers = 0) => {
|
|
127
|
-
if (config.basePath && config.dbScript) return config;
|
|
128
|
-
let filePath = pqb.getStackTrace()?.[3 + intermediateCallers]?.getFileName();
|
|
129
|
-
if (!filePath) {
|
|
130
|
-
throw new Error(
|
|
131
|
-
"Failed to determine path to db script. Please set basePath option of rakeDb"
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
if (filePath.startsWith("file://")) {
|
|
135
|
-
filePath = node_url.fileURLToPath(filePath);
|
|
136
|
-
}
|
|
137
|
-
const ext = path.extname(filePath);
|
|
138
|
-
if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
|
|
139
|
-
throw new Error(
|
|
140
|
-
`Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
config.basePath = path.dirname(filePath);
|
|
144
|
-
config.dbScript = path.basename(filePath);
|
|
145
|
-
return config;
|
|
333
|
+
const makeChange = (config) => (fn) => {
|
|
334
|
+
const change = { fn, config };
|
|
335
|
+
pushChange(change);
|
|
336
|
+
return change;
|
|
146
337
|
};
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
delete result.logger;
|
|
151
|
-
}
|
|
152
|
-
ensureBasePathAndDbScript(result, 1);
|
|
153
|
-
ensureMigrationsPath(result);
|
|
154
|
-
if (!result.recurrentPath) {
|
|
155
|
-
result.recurrentPath = path.join(
|
|
156
|
-
result.migrationsPath,
|
|
157
|
-
"recurrent"
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
if ("recurrentPath" in result && !path.isAbsolute(result.recurrentPath)) {
|
|
161
|
-
result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
|
|
162
|
-
}
|
|
163
|
-
if ("baseTable" in config && config.baseTable) {
|
|
164
|
-
const { types, snakeCase, language } = config.baseTable.prototype;
|
|
165
|
-
result.columnTypes = types || pqb.makeColumnTypes(pqb.defaultSchemaConfig);
|
|
166
|
-
if (snakeCase) result.snakeCase = true;
|
|
167
|
-
if (language) result.language = language;
|
|
168
|
-
} else {
|
|
169
|
-
const ct = "columnTypes" in config && config.columnTypes;
|
|
170
|
-
result.columnTypes = (typeof ct === "function" ? ct(
|
|
171
|
-
pqb.makeColumnTypes(pqb.defaultSchemaConfig)
|
|
172
|
-
) : ct) || pqb.makeColumnTypes(pqb.defaultSchemaConfig);
|
|
173
|
-
}
|
|
174
|
-
if (config.migrationId === "serial") {
|
|
175
|
-
result.migrationId = { serial: 4 };
|
|
176
|
-
}
|
|
177
|
-
const transaction = getCliParam(args, "transaction");
|
|
178
|
-
if (transaction) {
|
|
179
|
-
if (transaction !== "single" && transaction !== "per-migration") {
|
|
180
|
-
throw new Error(
|
|
181
|
-
`Unsupported transaction param ${transaction}, expected single or per-migration`
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
result.transaction = transaction;
|
|
185
|
-
} else if (!result.transaction) {
|
|
186
|
-
result.transaction = "single";
|
|
187
|
-
}
|
|
188
|
-
return result;
|
|
338
|
+
let currentChanges = [];
|
|
339
|
+
const clearChanges = () => {
|
|
340
|
+
currentChanges = [];
|
|
189
341
|
};
|
|
342
|
+
const getCurrentChanges = () => currentChanges;
|
|
343
|
+
const pushChange = (change) => currentChanges.push(change);
|
|
190
344
|
|
|
191
345
|
const versionToString = (config, version) => config.migrationId === "timestamp" ? `${version}` : `${version}`.padStart(config.migrationId.serial, "0");
|
|
192
|
-
const columnTypeToSql = (item) => {
|
|
193
|
-
return item.data.isOfCustomType ? item instanceof pqb.DomainColumn ? quoteNameFromString(item.dataType) : quoteCustomType(item.toSQL()) : item.toSQL();
|
|
346
|
+
const columnTypeToSql = (config, item) => {
|
|
347
|
+
return item.data.isOfCustomType ? item instanceof pqb.DomainColumn ? quoteNameFromString(config, item.dataType) : quoteCustomType(config, item.toSQL()) : item.toSQL();
|
|
194
348
|
};
|
|
195
349
|
const getColumnName = (item, key, snakeCase) => {
|
|
196
350
|
return item.data.name || (snakeCase ? pqb.toSnakeCase(key) : key);
|
|
197
351
|
};
|
|
198
|
-
const columnToSql = (name, item, values, hasMultiplePrimaryKeys, snakeCase) => {
|
|
199
|
-
const line = [`"${name}" ${columnTypeToSql(item)}`];
|
|
352
|
+
const columnToSql = (config, name, item, values, hasMultiplePrimaryKeys, snakeCase) => {
|
|
353
|
+
const line = [`"${name}" ${columnTypeToSql(config, item)}`];
|
|
200
354
|
if (item.data.compression) {
|
|
201
355
|
line.push(`COMPRESSION ${item.data.compression}`);
|
|
202
356
|
}
|
|
203
357
|
if (item.data.collate) {
|
|
204
|
-
line.push(`COLLATE ${quoteNameFromString(item.data.collate)}`);
|
|
358
|
+
line.push(`COLLATE ${quoteNameFromString(config, item.data.collate)}`);
|
|
205
359
|
}
|
|
206
360
|
if (item.data.identity) {
|
|
207
|
-
line.push(identityToSql(item.data.identity));
|
|
361
|
+
line.push(identityToSql(config, item.data.identity));
|
|
208
362
|
} else if (item.data.generated) {
|
|
209
363
|
line.push(
|
|
210
364
|
`GENERATED ALWAYS AS (${item.data.generated.toSQL({
|
|
@@ -238,6 +392,7 @@ const columnToSql = (name, item, values, hasMultiplePrimaryKeys, snakeCase) => {
|
|
|
238
392
|
}
|
|
239
393
|
line.push(
|
|
240
394
|
referencesToSql(
|
|
395
|
+
config,
|
|
241
396
|
{
|
|
242
397
|
columns: [name],
|
|
243
398
|
...foreignKey
|
|
@@ -261,11 +416,11 @@ const encodeColumnDefault = (def, values, column) => {
|
|
|
261
416
|
}
|
|
262
417
|
return null;
|
|
263
418
|
};
|
|
264
|
-
const identityToSql = (identity) => {
|
|
265
|
-
const options = sequenceOptionsToSql(identity);
|
|
419
|
+
const identityToSql = (config, identity) => {
|
|
420
|
+
const options = sequenceOptionsToSql(config, identity);
|
|
266
421
|
return `GENERATED ${identity.always ? "ALWAYS" : "BY DEFAULT"} AS IDENTITY${options ? ` (${options})` : ""}`;
|
|
267
422
|
};
|
|
268
|
-
const sequenceOptionsToSql = (item) => {
|
|
423
|
+
const sequenceOptionsToSql = (config, item) => {
|
|
269
424
|
const line = [];
|
|
270
425
|
if (item.dataType) line.push(`AS ${item.dataType}`);
|
|
271
426
|
if (item.increment !== void 0) line.push(`INCREMENT BY ${item.increment}`);
|
|
@@ -275,7 +430,7 @@ const sequenceOptionsToSql = (item) => {
|
|
|
275
430
|
if (item.cache !== void 0) line.push(`CACHE ${item.cache}`);
|
|
276
431
|
if (item.cycle) line.push(`CYCLE`);
|
|
277
432
|
if (item.ownedBy) {
|
|
278
|
-
const [schema, table] = getSchemaAndTableFromName(item.ownedBy);
|
|
433
|
+
const [schema, table] = getSchemaAndTableFromName(config, item.ownedBy);
|
|
279
434
|
line.push(`OWNED BY ${quoteTable(schema, table)}`);
|
|
280
435
|
}
|
|
281
436
|
return line.join(" ");
|
|
@@ -305,9 +460,9 @@ const addColumnComment = (comments, name, item) => {
|
|
|
305
460
|
comments.push({ column: name, comment: item.data.comment });
|
|
306
461
|
}
|
|
307
462
|
};
|
|
308
|
-
const getForeignKeyTable = (fnOrTable) => {
|
|
463
|
+
const getForeignKeyTable = (config, fnOrTable) => {
|
|
309
464
|
if (typeof fnOrTable === "string") {
|
|
310
|
-
return getSchemaAndTableFromName(fnOrTable);
|
|
465
|
+
return getSchemaAndTableFromName(config, fnOrTable);
|
|
311
466
|
}
|
|
312
467
|
const item = new (fnOrTable())();
|
|
313
468
|
return [item.schema, item.table];
|
|
@@ -324,7 +479,7 @@ const getConstraintName = (table, constraint, snakeCase) => {
|
|
|
324
479
|
if (constraint.identity) return `${table}_identity`;
|
|
325
480
|
return `${table}_constraint`;
|
|
326
481
|
};
|
|
327
|
-
const constraintToSql = ({ name }, up, constraint, values, snakeCase) => {
|
|
482
|
+
const constraintToSql = (config, { name }, up, constraint, values, snakeCase) => {
|
|
328
483
|
const constraintName = constraint.name || getConstraintName(name, constraint, snakeCase);
|
|
329
484
|
if (!up) {
|
|
330
485
|
const { dropMode } = constraint;
|
|
@@ -332,7 +487,7 @@ const constraintToSql = ({ name }, up, constraint, values, snakeCase) => {
|
|
|
332
487
|
}
|
|
333
488
|
const sql = [`CONSTRAINT "${constraintName}"`];
|
|
334
489
|
if (constraint.references) {
|
|
335
|
-
sql.push(foreignKeyToSql(constraint.references, snakeCase));
|
|
490
|
+
sql.push(foreignKeyToSql(config, constraint.references, snakeCase));
|
|
336
491
|
}
|
|
337
492
|
if (constraint.check) {
|
|
338
493
|
sql.push(checkToSql(constraint.check, values));
|
|
@@ -342,13 +497,13 @@ const constraintToSql = ({ name }, up, constraint, values, snakeCase) => {
|
|
|
342
497
|
const checkToSql = (check, values) => {
|
|
343
498
|
return `CHECK (${check.toSQL({ values })})`;
|
|
344
499
|
};
|
|
345
|
-
const foreignKeyToSql = (item, snakeCase) => {
|
|
500
|
+
const foreignKeyToSql = (config, item, snakeCase) => {
|
|
346
501
|
return `FOREIGN KEY (${joinColumns(
|
|
347
502
|
snakeCase ? item.columns.map(pqb.toSnakeCase) : item.columns
|
|
348
|
-
)}) ${referencesToSql(item, snakeCase)}`;
|
|
503
|
+
)}) ${referencesToSql(config, item, snakeCase)}`;
|
|
349
504
|
};
|
|
350
|
-
const referencesToSql = (references, snakeCase) => {
|
|
351
|
-
const [schema, table] = getForeignKeyTable(references.fnOrTable);
|
|
505
|
+
const referencesToSql = (config, references, snakeCase) => {
|
|
506
|
+
const [schema, table] = getForeignKeyTable(config, references.fnOrTable);
|
|
352
507
|
const sql = [
|
|
353
508
|
`REFERENCES ${quoteTable(schema, table)}(${joinColumns(
|
|
354
509
|
snakeCase ? references.foreignColumns.map(pqb.toSnakeCase) : references.foreignColumns
|
|
@@ -399,7 +554,7 @@ const getIndexOrExcludeName = (table, columns, suffix) => makeConstraintName(
|
|
|
399
554
|
);
|
|
400
555
|
const getIndexName = (table, columns) => getIndexOrExcludeName(table, columns, "idx");
|
|
401
556
|
const getExcludeName = (table, columns) => getIndexOrExcludeName(table, columns, "exclude");
|
|
402
|
-
const indexesToQuery = (up, { schema, name: tableName }, indexes, snakeCase, language) => {
|
|
557
|
+
const indexesToQuery = (config, up, { schema, name: tableName }, indexes, snakeCase, language) => {
|
|
403
558
|
return indexes.map((index) => {
|
|
404
559
|
const { options } = index;
|
|
405
560
|
const { columns, include, name } = getIndexOrExcludeMainOptions(
|
|
@@ -428,7 +583,7 @@ const indexesToQuery = (up, { schema, name: tableName }, indexes, snakeCase, lan
|
|
|
428
583
|
const columnsSql = columns.map((column) => {
|
|
429
584
|
let sql2 = [
|
|
430
585
|
"expression" in column ? `(${column.expression})` : `"${column.column}"`,
|
|
431
|
-
column.collate && `COLLATE ${quoteNameFromString(column.collate)}`,
|
|
586
|
+
column.collate && `COLLATE ${quoteNameFromString(config, column.collate)}`,
|
|
432
587
|
column.opclass,
|
|
433
588
|
column.order
|
|
434
589
|
].filter((x) => !!x).join(" ");
|
|
@@ -472,7 +627,7 @@ const indexesToQuery = (up, { schema, name: tableName }, indexes, snakeCase, lan
|
|
|
472
627
|
return { text: sql.join(" "), values };
|
|
473
628
|
});
|
|
474
629
|
};
|
|
475
|
-
const excludesToQuery = (up, { schema, name: tableName }, excludes, snakeCase) => {
|
|
630
|
+
const excludesToQuery = (config, up, { schema, name: tableName }, excludes, snakeCase) => {
|
|
476
631
|
return excludes.map((exclude) => {
|
|
477
632
|
const { options } = exclude;
|
|
478
633
|
const { columns, include, name } = getIndexOrExcludeMainOptions(
|
|
@@ -492,7 +647,7 @@ const excludesToQuery = (up, { schema, name: tableName }, excludes, snakeCase) =
|
|
|
492
647
|
const columnList = columns.map(
|
|
493
648
|
(column) => [
|
|
494
649
|
"expression" in column ? `(${column.expression})` : `"${column.column}"`,
|
|
495
|
-
column.collate && `COLLATE ${quoteNameFromString(column.collate)}`,
|
|
650
|
+
column.collate && `COLLATE ${quoteNameFromString(config, column.collate)}`,
|
|
496
651
|
column.opclass,
|
|
497
652
|
column.order,
|
|
498
653
|
`WITH ${column.with}`
|
|
@@ -561,9 +716,16 @@ const cmpRawSql = (a, b) => {
|
|
|
561
716
|
};
|
|
562
717
|
const getMigrationsSchemaAndTable = (config) => {
|
|
563
718
|
const [tableSchema, table] = getSchemaAndTableFromName(
|
|
719
|
+
config,
|
|
564
720
|
config.migrationsTable
|
|
565
721
|
);
|
|
566
|
-
|
|
722
|
+
let schema = tableSchema;
|
|
723
|
+
if (!schema) {
|
|
724
|
+
schema = typeof config.schema === "function" ? config.schema() : config.schema;
|
|
725
|
+
if (schema === "public") {
|
|
726
|
+
schema = void 0;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
567
729
|
return { schema, table };
|
|
568
730
|
};
|
|
569
731
|
const migrationsSchemaTableSql = (config) => {
|
|
@@ -582,6 +744,11 @@ const tableMethods = {
|
|
|
582
744
|
}
|
|
583
745
|
};
|
|
584
746
|
|
|
747
|
+
class RakeDbError extends Error {
|
|
748
|
+
}
|
|
749
|
+
class NoPrimaryKey extends RakeDbError {
|
|
750
|
+
}
|
|
751
|
+
|
|
585
752
|
const createTable = async (migration, up, tableName, first, second, third) => {
|
|
586
753
|
let options;
|
|
587
754
|
let fn;
|
|
@@ -620,6 +787,7 @@ const createTable = async (migration, up, tableName, first, second, third) => {
|
|
|
620
787
|
shape = tableData = pqb.emptyObject;
|
|
621
788
|
}
|
|
622
789
|
const ast = makeAst$2(
|
|
790
|
+
migration.options,
|
|
623
791
|
up,
|
|
624
792
|
tableName,
|
|
625
793
|
shape,
|
|
@@ -628,7 +796,7 @@ const createTable = async (migration, up, tableName, first, second, third) => {
|
|
|
628
796
|
migration.options.noPrimaryKey
|
|
629
797
|
);
|
|
630
798
|
fn && validatePrimaryKey(ast);
|
|
631
|
-
const queries = astToQueries$1(ast, snakeCase, language);
|
|
799
|
+
const queries = astToQueries$1(migration.options, ast, snakeCase, language);
|
|
632
800
|
for (const { then, ...query } of queries) {
|
|
633
801
|
const result = await migration.adapter.arrays(interpolateSqlValues(query));
|
|
634
802
|
then?.(result);
|
|
@@ -648,7 +816,7 @@ const createTable = async (migration, up, tableName, first, second, third) => {
|
|
|
648
816
|
}
|
|
649
817
|
};
|
|
650
818
|
};
|
|
651
|
-
const makeAst$2 = (up, tableName, shape, tableData, options, noPrimaryKey) => {
|
|
819
|
+
const makeAst$2 = (config, up, tableName, shape, tableData, options, noPrimaryKey) => {
|
|
652
820
|
const shapePKeys = [];
|
|
653
821
|
for (const key in shape) {
|
|
654
822
|
const column = shape[key];
|
|
@@ -657,7 +825,7 @@ const makeAst$2 = (up, tableName, shape, tableData, options, noPrimaryKey) => {
|
|
|
657
825
|
}
|
|
658
826
|
}
|
|
659
827
|
const { primaryKey } = tableData;
|
|
660
|
-
const [schema, table] = getSchemaAndTableFromName(tableName);
|
|
828
|
+
const [schema, table] = getSchemaAndTableFromName(config, tableName);
|
|
661
829
|
return {
|
|
662
830
|
type: "table",
|
|
663
831
|
action: up ? "create" : "drop",
|
|
@@ -697,13 +865,13 @@ You can suppress this error by setting { noPrimaryKey: true } after a table name
|
|
|
697
865
|
}
|
|
698
866
|
}
|
|
699
867
|
};
|
|
700
|
-
const astToQueries$1 = (ast, snakeCase, language) => {
|
|
868
|
+
const astToQueries$1 = (config, ast, snakeCase, language) => {
|
|
701
869
|
const queries = [];
|
|
702
870
|
const { shape } = ast;
|
|
703
871
|
for (const key in shape) {
|
|
704
872
|
const item = shape[key];
|
|
705
873
|
if (!(item instanceof pqb.EnumColumn)) continue;
|
|
706
|
-
queries.push(makePopulateEnumQuery(item));
|
|
874
|
+
queries.push(makePopulateEnumQuery(config, item));
|
|
707
875
|
}
|
|
708
876
|
if (ast.action === "drop") {
|
|
709
877
|
queries.push({
|
|
@@ -724,7 +892,14 @@ const astToQueries$1 = (ast, snakeCase, language) => {
|
|
|
724
892
|
addColumnComment(comments, name, item);
|
|
725
893
|
lines.push(
|
|
726
894
|
`
|
|
727
|
-
${columnToSql(
|
|
895
|
+
${columnToSql(
|
|
896
|
+
config,
|
|
897
|
+
name,
|
|
898
|
+
item,
|
|
899
|
+
values,
|
|
900
|
+
!!ast.primaryKey,
|
|
901
|
+
snakeCase
|
|
902
|
+
)}`
|
|
728
903
|
);
|
|
729
904
|
}
|
|
730
905
|
if (ast.primaryKey) {
|
|
@@ -742,6 +917,7 @@ const astToQueries$1 = (ast, snakeCase, language) => {
|
|
|
742
917
|
lines.push(
|
|
743
918
|
`
|
|
744
919
|
${constraintToSql(
|
|
920
|
+
config,
|
|
745
921
|
ast,
|
|
746
922
|
true,
|
|
747
923
|
{
|
|
@@ -766,8 +942,8 @@ const astToQueries$1 = (ast, snakeCase, language) => {
|
|
|
766
942
|
)`,
|
|
767
943
|
values
|
|
768
944
|
},
|
|
769
|
-
...indexesToQuery(true, ast, indexes, snakeCase, language),
|
|
770
|
-
...excludesToQuery(true, ast, excludes, snakeCase),
|
|
945
|
+
...indexesToQuery(config, true, ast, indexes, snakeCase, language),
|
|
946
|
+
...excludesToQuery(config, true, ast, excludes, snakeCase),
|
|
771
947
|
...commentsToQuery(ast, comments)
|
|
772
948
|
);
|
|
773
949
|
if (ast.comment) {
|
|
@@ -989,14 +1165,21 @@ const changeTable = async (migration, up, tableName, options, fn) => {
|
|
|
989
1165
|
tableChanger[pqb.snakeCaseKey] = snakeCase;
|
|
990
1166
|
addOrDropChanges.length = 0;
|
|
991
1167
|
const changeData = fn?.(tableChanger) || {};
|
|
992
|
-
const ast = makeAst$1(
|
|
993
|
-
|
|
1168
|
+
const ast = makeAst$1(
|
|
1169
|
+
migration.options,
|
|
1170
|
+
up,
|
|
1171
|
+
tableName,
|
|
1172
|
+
changeData,
|
|
1173
|
+
changeTableData,
|
|
1174
|
+
options
|
|
1175
|
+
);
|
|
1176
|
+
const queries = astToQueries(migration.options, ast, snakeCase, language);
|
|
994
1177
|
for (const query of queries) {
|
|
995
1178
|
const result = await migration.adapter.arrays(interpolateSqlValues(query));
|
|
996
1179
|
query.then?.(result);
|
|
997
1180
|
}
|
|
998
1181
|
};
|
|
999
|
-
const makeAst$1 = (up, name, changeData, changeTableData2, options) => {
|
|
1182
|
+
const makeAst$1 = (config, up, name, changeData, changeTableData2, options) => {
|
|
1000
1183
|
const { comment } = options;
|
|
1001
1184
|
const shape = {};
|
|
1002
1185
|
const consumedChanges = {};
|
|
@@ -1041,7 +1224,7 @@ const makeAst$1 = (up, name, changeData, changeTableData2, options) => {
|
|
|
1041
1224
|
);
|
|
1042
1225
|
shape[name2] = arr;
|
|
1043
1226
|
}
|
|
1044
|
-
const [schema, table] = getSchemaAndTableFromName(name);
|
|
1227
|
+
const [schema, table] = getSchemaAndTableFromName(config, name);
|
|
1045
1228
|
return {
|
|
1046
1229
|
type: "changeTable",
|
|
1047
1230
|
schema,
|
|
@@ -1051,7 +1234,7 @@ const makeAst$1 = (up, name, changeData, changeTableData2, options) => {
|
|
|
1051
1234
|
...up ? changeTableData2 : { add: changeTableData2.drop, drop: changeTableData2.add }
|
|
1052
1235
|
};
|
|
1053
1236
|
};
|
|
1054
|
-
const astToQueries = (ast, snakeCase, language) => {
|
|
1237
|
+
const astToQueries = (config, ast, snakeCase, language) => {
|
|
1055
1238
|
const queries = [];
|
|
1056
1239
|
if (ast.comment !== void 0) {
|
|
1057
1240
|
queries.push({
|
|
@@ -1071,6 +1254,7 @@ const astToQueries = (ast, snakeCase, language) => {
|
|
|
1071
1254
|
if (Array.isArray(item)) {
|
|
1072
1255
|
for (const it of item) {
|
|
1073
1256
|
handlePrerequisitesForTableItem(
|
|
1257
|
+
config,
|
|
1074
1258
|
key,
|
|
1075
1259
|
it,
|
|
1076
1260
|
queries,
|
|
@@ -1081,6 +1265,7 @@ const astToQueries = (ast, snakeCase, language) => {
|
|
|
1081
1265
|
}
|
|
1082
1266
|
} else {
|
|
1083
1267
|
handlePrerequisitesForTableItem(
|
|
1268
|
+
config,
|
|
1084
1269
|
key,
|
|
1085
1270
|
item,
|
|
1086
1271
|
queries,
|
|
@@ -1119,6 +1304,7 @@ const astToQueries = (ast, snakeCase, language) => {
|
|
|
1119
1304
|
if (Array.isArray(item)) {
|
|
1120
1305
|
for (const it of item) {
|
|
1121
1306
|
handleTableItemChange(
|
|
1307
|
+
config,
|
|
1122
1308
|
key,
|
|
1123
1309
|
it,
|
|
1124
1310
|
ast,
|
|
@@ -1138,6 +1324,7 @@ const astToQueries = (ast, snakeCase, language) => {
|
|
|
1138
1324
|
}
|
|
1139
1325
|
} else {
|
|
1140
1326
|
handleTableItemChange(
|
|
1327
|
+
config,
|
|
1141
1328
|
key,
|
|
1142
1329
|
item,
|
|
1143
1330
|
ast,
|
|
@@ -1170,7 +1357,14 @@ const astToQueries = (ast, snakeCase, language) => {
|
|
|
1170
1357
|
prependAlterTable.push(
|
|
1171
1358
|
...dropConstraints.map(
|
|
1172
1359
|
(foreignKey) => `
|
|
1173
|
-
DROP ${constraintToSql(
|
|
1360
|
+
DROP ${constraintToSql(
|
|
1361
|
+
config,
|
|
1362
|
+
ast,
|
|
1363
|
+
false,
|
|
1364
|
+
foreignKey,
|
|
1365
|
+
values,
|
|
1366
|
+
snakeCase
|
|
1367
|
+
)}`
|
|
1174
1368
|
)
|
|
1175
1369
|
);
|
|
1176
1370
|
alterTable.unshift(...prependAlterTable);
|
|
@@ -1188,7 +1382,14 @@ const astToQueries = (ast, snakeCase, language) => {
|
|
|
1188
1382
|
alterTable.push(
|
|
1189
1383
|
...addConstraints.map(
|
|
1190
1384
|
(foreignKey) => `
|
|
1191
|
-
ADD ${constraintToSql(
|
|
1385
|
+
ADD ${constraintToSql(
|
|
1386
|
+
config,
|
|
1387
|
+
ast,
|
|
1388
|
+
true,
|
|
1389
|
+
foreignKey,
|
|
1390
|
+
values,
|
|
1391
|
+
snakeCase
|
|
1392
|
+
)}`
|
|
1192
1393
|
)
|
|
1193
1394
|
);
|
|
1194
1395
|
const tableName = quoteWithSchema(ast);
|
|
@@ -1204,10 +1405,14 @@ const astToQueries = (ast, snakeCase, language) => {
|
|
|
1204
1405
|
if (alterTable.length) {
|
|
1205
1406
|
queries.push(alterTableSql(tableName, alterTable, values));
|
|
1206
1407
|
}
|
|
1207
|
-
queries.push(
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
queries.push(
|
|
1408
|
+
queries.push(
|
|
1409
|
+
...indexesToQuery(config, false, ast, dropIndexes, snakeCase, language)
|
|
1410
|
+
);
|
|
1411
|
+
queries.push(
|
|
1412
|
+
...indexesToQuery(config, true, ast, addIndexes, snakeCase, language)
|
|
1413
|
+
);
|
|
1414
|
+
queries.push(...excludesToQuery(config, false, ast, dropExcludes, snakeCase));
|
|
1415
|
+
queries.push(...excludesToQuery(config, true, ast, addExcludes, snakeCase));
|
|
1211
1416
|
queries.push(...commentsToQuery(ast, comments));
|
|
1212
1417
|
return queries;
|
|
1213
1418
|
};
|
|
@@ -1216,11 +1421,11 @@ const alterTableSql = (tableName, lines, values) => ({
|
|
|
1216
1421
|
${lines.join(",\n ")}`,
|
|
1217
1422
|
values
|
|
1218
1423
|
});
|
|
1219
|
-
const handlePrerequisitesForTableItem = (key, item, queries, addPrimaryKeys, dropPrimaryKeys, snakeCase) => {
|
|
1424
|
+
const handlePrerequisitesForTableItem = (config, key, item, queries, addPrimaryKeys, dropPrimaryKeys, snakeCase) => {
|
|
1220
1425
|
if ("item" in item) {
|
|
1221
1426
|
const { item: column } = item;
|
|
1222
1427
|
if (column instanceof pqb.EnumColumn) {
|
|
1223
|
-
queries.push(makePopulateEnumQuery(column));
|
|
1428
|
+
queries.push(makePopulateEnumQuery(config, column));
|
|
1224
1429
|
}
|
|
1225
1430
|
}
|
|
1226
1431
|
if (item.type === "add") {
|
|
@@ -1233,10 +1438,10 @@ const handlePrerequisitesForTableItem = (key, item, queries, addPrimaryKeys, dro
|
|
|
1233
1438
|
}
|
|
1234
1439
|
} else if (item.type === "change") {
|
|
1235
1440
|
if (item.from.column instanceof pqb.EnumColumn) {
|
|
1236
|
-
queries.push(makePopulateEnumQuery(item.from.column));
|
|
1441
|
+
queries.push(makePopulateEnumQuery(config, item.from.column));
|
|
1237
1442
|
}
|
|
1238
1443
|
if (item.to.column instanceof pqb.EnumColumn) {
|
|
1239
|
-
queries.push(makePopulateEnumQuery(item.to.column));
|
|
1444
|
+
queries.push(makePopulateEnumQuery(config, item.to.column));
|
|
1240
1445
|
}
|
|
1241
1446
|
if (item.from.primaryKey) {
|
|
1242
1447
|
dropPrimaryKeys.columns.push(
|
|
@@ -1252,7 +1457,7 @@ const handlePrerequisitesForTableItem = (key, item, queries, addPrimaryKeys, dro
|
|
|
1252
1457
|
}
|
|
1253
1458
|
}
|
|
1254
1459
|
};
|
|
1255
|
-
const handleTableItemChange = (key, item, ast, alterTable, renameItems, values, addPrimaryKeys, addIndexes, dropIndexes, addExcludes, dropExcludes, addConstraints, dropConstraints, comments, snakeCase) => {
|
|
1460
|
+
const handleTableItemChange = (config, key, item, ast, alterTable, renameItems, values, addPrimaryKeys, addIndexes, dropIndexes, addExcludes, dropExcludes, addConstraints, dropConstraints, comments, snakeCase) => {
|
|
1256
1461
|
if (item.type === "add") {
|
|
1257
1462
|
const column = item.item;
|
|
1258
1463
|
const name = getColumnName(column, key, snakeCase);
|
|
@@ -1261,6 +1466,7 @@ const handleTableItemChange = (key, item, ast, alterTable, renameItems, values,
|
|
|
1261
1466
|
addColumnComment(comments, name, column);
|
|
1262
1467
|
alterTable.push(
|
|
1263
1468
|
`ADD COLUMN ${columnToSql(
|
|
1469
|
+
config,
|
|
1264
1470
|
name,
|
|
1265
1471
|
column,
|
|
1266
1472
|
values,
|
|
@@ -1283,10 +1489,10 @@ const handleTableItemChange = (key, item, ast, alterTable, renameItems, values,
|
|
|
1283
1489
|
let changeType = false;
|
|
1284
1490
|
if (to.type && (from.type !== to.type || from.collate !== to.collate)) {
|
|
1285
1491
|
changeType = true;
|
|
1286
|
-
const type = !to.column || to.column.data.isOfCustomType ? to.column && to.column instanceof pqb.DomainColumn ? quoteNameFromString(to.type) : quoteCustomType(to.type) : to.type;
|
|
1492
|
+
const type = !to.column || to.column.data.isOfCustomType ? to.column && to.column instanceof pqb.DomainColumn ? quoteNameFromString(config, to.type) : quoteCustomType(config, to.type) : to.type;
|
|
1287
1493
|
const using = item.using?.usingUp ? ` USING ${item.using.usingUp.toSQL({ values })}` : to.column instanceof pqb.EnumColumn ? ` USING "${name}"::text::${type}` : to.column instanceof pqb.ArrayColumn ? ` USING "${name}"::text[]::${type}` : "";
|
|
1288
1494
|
alterTable.push(
|
|
1289
|
-
`ALTER COLUMN "${name}" TYPE ${type}${to.collate ? ` COLLATE ${quoteNameFromString(to.collate)}` : ""}${using}`
|
|
1495
|
+
`ALTER COLUMN "${name}" TYPE ${type}${to.collate ? ` COLLATE ${quoteNameFromString(config, to.collate)}` : ""}${using}`
|
|
1290
1496
|
);
|
|
1291
1497
|
}
|
|
1292
1498
|
if (typeof from.identity !== typeof to.identity || !pqb.deepCompare(from.identity, to.identity)) {
|
|
@@ -1295,7 +1501,7 @@ const handleTableItemChange = (key, item, ast, alterTable, renameItems, values,
|
|
|
1295
1501
|
}
|
|
1296
1502
|
if (to.identity) {
|
|
1297
1503
|
alterTable.push(
|
|
1298
|
-
`ALTER COLUMN "${name}" ADD ${identityToSql(to.identity)}`
|
|
1504
|
+
`ALTER COLUMN "${name}" ADD ${identityToSql(config, to.identity)}`
|
|
1299
1505
|
);
|
|
1300
1506
|
}
|
|
1301
1507
|
}
|
|
@@ -1428,15 +1634,15 @@ const renameColumnSql = (from, to) => {
|
|
|
1428
1634
|
};
|
|
1429
1635
|
|
|
1430
1636
|
const createView = async (migration, up, name, options, sql) => {
|
|
1431
|
-
const ast = makeAst(up, name, options, sql);
|
|
1637
|
+
const ast = makeAst(migration.options, up, name, options, sql);
|
|
1432
1638
|
const query = astToQuery(ast);
|
|
1433
1639
|
await migration.adapter.arrays(interpolateSqlValues(query));
|
|
1434
1640
|
};
|
|
1435
|
-
const makeAst = (up, fullName, options, sql) => {
|
|
1641
|
+
const makeAst = (config, up, fullName, options, sql) => {
|
|
1436
1642
|
if (typeof sql === "string") {
|
|
1437
1643
|
sql = pqb.raw({ raw: sql });
|
|
1438
1644
|
}
|
|
1439
|
-
const [schema, name] = getSchemaAndTableFromName(fullName);
|
|
1645
|
+
const [schema, name] = getSchemaAndTableFromName(config, fullName);
|
|
1440
1646
|
return {
|
|
1441
1647
|
type: "view",
|
|
1442
1648
|
action: up ? "create" : "drop",
|
|
@@ -2028,7 +2234,7 @@ class Migration {
|
|
|
2028
2234
|
* @param values - object where keys are for old names, values are for new names
|
|
2029
2235
|
*/
|
|
2030
2236
|
async renameEnumValues(enumName, values) {
|
|
2031
|
-
const [schema, name] = getSchemaAndTableFromName(enumName);
|
|
2237
|
+
const [schema, name] = getSchemaAndTableFromName(this.options, enumName);
|
|
2032
2238
|
const ast = {
|
|
2033
2239
|
type: "renameEnumValues",
|
|
2034
2240
|
schema,
|
|
@@ -2292,9 +2498,16 @@ class Migration {
|
|
|
2292
2498
|
* @param tableName - name of the table
|
|
2293
2499
|
*/
|
|
2294
2500
|
async tableExists(tableName) {
|
|
2501
|
+
let text = `SELECT 1 FROM "information_schema"."tables" WHERE "table_name" = $1`;
|
|
2502
|
+
const [schema, table] = getSchemaAndTableFromName(this.options, tableName);
|
|
2503
|
+
const values = [table];
|
|
2504
|
+
if (schema) {
|
|
2505
|
+
text += ' AND "table_schema" = $2';
|
|
2506
|
+
values.push(schema);
|
|
2507
|
+
}
|
|
2295
2508
|
return queryExists(this, {
|
|
2296
|
-
text
|
|
2297
|
-
values
|
|
2509
|
+
text,
|
|
2510
|
+
values
|
|
2298
2511
|
});
|
|
2299
2512
|
}
|
|
2300
2513
|
/**
|
|
@@ -2316,12 +2529,19 @@ class Migration {
|
|
|
2316
2529
|
* @param columnName - name of the column
|
|
2317
2530
|
*/
|
|
2318
2531
|
async columnExists(tableName, columnName) {
|
|
2532
|
+
let text = `SELECT 1 FROM "information_schema"."columns" WHERE "table_name" = $1 AND "column_name" = $2`;
|
|
2533
|
+
const [schema, table] = getSchemaAndTableFromName(this.options, tableName);
|
|
2534
|
+
const values = [
|
|
2535
|
+
table,
|
|
2536
|
+
this.options.snakeCase ? pqb.toSnakeCase(columnName) : columnName
|
|
2537
|
+
];
|
|
2538
|
+
if (schema) {
|
|
2539
|
+
text += ' AND "table_schema" = $3';
|
|
2540
|
+
values.push(schema);
|
|
2541
|
+
}
|
|
2319
2542
|
return queryExists(this, {
|
|
2320
|
-
text
|
|
2321
|
-
values
|
|
2322
|
-
tableName,
|
|
2323
|
-
this.options.snakeCase ? pqb.toSnakeCase(columnName) : columnName
|
|
2324
|
-
]
|
|
2543
|
+
text,
|
|
2544
|
+
values
|
|
2325
2545
|
});
|
|
2326
2546
|
}
|
|
2327
2547
|
/**
|
|
@@ -2401,7 +2621,7 @@ const createSchema = async (migration, up, name) => {
|
|
|
2401
2621
|
);
|
|
2402
2622
|
};
|
|
2403
2623
|
const createExtension = async (migration, up, fullName, options) => {
|
|
2404
|
-
const [schema, name] = getSchemaAndTableFromName(fullName);
|
|
2624
|
+
const [schema, name] = getSchemaAndTableFromName(migration.options, fullName);
|
|
2405
2625
|
const ast = {
|
|
2406
2626
|
type: "extension",
|
|
2407
2627
|
action: up ? "create" : "drop",
|
|
@@ -2418,7 +2638,7 @@ const createExtension = async (migration, up, fullName, options) => {
|
|
|
2418
2638
|
await migration.adapter.query(query);
|
|
2419
2639
|
};
|
|
2420
2640
|
const createEnum = async (migration, up, name, values, options = {}) => {
|
|
2421
|
-
const [schema, enumName] = getSchemaAndTableFromName(name);
|
|
2641
|
+
const [schema, enumName] = getSchemaAndTableFromName(migration.options, name);
|
|
2422
2642
|
const ast = {
|
|
2423
2643
|
type: "enum",
|
|
2424
2644
|
action: up ? "create" : "drop",
|
|
@@ -2437,7 +2657,10 @@ const createEnum = async (migration, up, name, values, options = {}) => {
|
|
|
2437
2657
|
await migration.adapter.query(query);
|
|
2438
2658
|
};
|
|
2439
2659
|
const createDomain = async (migration, up, name, fn) => {
|
|
2440
|
-
const [schema, domainName] = getSchemaAndTableFromName(
|
|
2660
|
+
const [schema, domainName] = getSchemaAndTableFromName(
|
|
2661
|
+
migration.options,
|
|
2662
|
+
name
|
|
2663
|
+
);
|
|
2441
2664
|
const ast = {
|
|
2442
2665
|
type: "domain",
|
|
2443
2666
|
action: up ? "create" : "drop",
|
|
@@ -2450,7 +2673,10 @@ const createDomain = async (migration, up, name, fn) => {
|
|
|
2450
2673
|
const quotedName = quoteWithSchema(ast);
|
|
2451
2674
|
if (ast.action === "create") {
|
|
2452
2675
|
const column = ast.baseType;
|
|
2453
|
-
query = `CREATE DOMAIN ${quotedName} AS ${columnTypeToSql(
|
|
2676
|
+
query = `CREATE DOMAIN ${quotedName} AS ${columnTypeToSql(
|
|
2677
|
+
migration.options,
|
|
2678
|
+
column
|
|
2679
|
+
)}${column.data.collate ? `
|
|
2454
2680
|
COLLATE "${column.data.collate}"` : ""}${column.data.default !== void 0 ? `
|
|
2455
2681
|
DEFAULT ${encodeColumnDefault(column.data.default, values)}` : ""}${!column.data.isNullable || column.data.checks ? "\n" : ""}${[
|
|
2456
2682
|
!column.data.isNullable && "NOT NULL",
|
|
@@ -2467,7 +2693,10 @@ DEFAULT ${encodeColumnDefault(column.data.default, values)}` : ""}${!column.data
|
|
|
2467
2693
|
);
|
|
2468
2694
|
};
|
|
2469
2695
|
const createCollation = async (migration, up, name, options) => {
|
|
2470
|
-
const [schema, collationName] = getSchemaAndTableFromName(
|
|
2696
|
+
const [schema, collationName] = getSchemaAndTableFromName(
|
|
2697
|
+
migration.options,
|
|
2698
|
+
name
|
|
2699
|
+
);
|
|
2471
2700
|
const ast = {
|
|
2472
2701
|
type: "collation",
|
|
2473
2702
|
action: up ? "create" : "drop",
|
|
@@ -2480,7 +2709,10 @@ const createCollation = async (migration, up, name, options) => {
|
|
|
2480
2709
|
if (ast.action === "create") {
|
|
2481
2710
|
query = `CREATE COLLATION${ast.createIfNotExists ? " IF NOT EXISTS" : ""} ${quotedName} `;
|
|
2482
2711
|
if (ast.fromExisting) {
|
|
2483
|
-
query += `FROM ${quoteNameFromString(
|
|
2712
|
+
query += `FROM ${quoteNameFromString(
|
|
2713
|
+
migration.options,
|
|
2714
|
+
ast.fromExisting
|
|
2715
|
+
)}`;
|
|
2484
2716
|
} else {
|
|
2485
2717
|
const config = [];
|
|
2486
2718
|
if (ast.locale) config.push(`locale = '${ast.locale}'`);
|
|
@@ -2503,8 +2735,14 @@ const queryExists = (db, sql) => {
|
|
|
2503
2735
|
return db.adapter.query(sql.text, sql.values).then(({ rowCount }) => rowCount > 0);
|
|
2504
2736
|
};
|
|
2505
2737
|
const renameType = async (migration, from, to, kind) => {
|
|
2506
|
-
const [fromSchema, f] = getSchemaAndTableFromName(
|
|
2507
|
-
|
|
2738
|
+
const [fromSchema, f] = getSchemaAndTableFromName(
|
|
2739
|
+
migration.options,
|
|
2740
|
+
migration.up ? from : to
|
|
2741
|
+
);
|
|
2742
|
+
const [toSchema, t] = getSchemaAndTableFromName(
|
|
2743
|
+
migration.options,
|
|
2744
|
+
migration.up ? to : from
|
|
2745
|
+
);
|
|
2508
2746
|
const ast = {
|
|
2509
2747
|
type: "renameType",
|
|
2510
2748
|
kind,
|
|
@@ -2525,7 +2763,10 @@ const renameType = async (migration, from, to, kind) => {
|
|
|
2525
2763
|
}
|
|
2526
2764
|
};
|
|
2527
2765
|
const renameTableItem = async (migration, tableName, from, to, kind) => {
|
|
2528
|
-
const [schema, table] = getSchemaAndTableFromName(
|
|
2766
|
+
const [schema, table] = getSchemaAndTableFromName(
|
|
2767
|
+
migration.options,
|
|
2768
|
+
tableName
|
|
2769
|
+
);
|
|
2529
2770
|
const [f, t] = migration.up ? [from, to] : [to, from];
|
|
2530
2771
|
await migration.adapter.query(
|
|
2531
2772
|
kind === "INDEX" ? `ALTER INDEX ${quoteTable(schema, f)} RENAME TO "${t}"` : `ALTER TABLE ${quoteTable(
|
|
@@ -2535,7 +2776,7 @@ const renameTableItem = async (migration, tableName, from, to, kind) => {
|
|
|
2535
2776
|
);
|
|
2536
2777
|
};
|
|
2537
2778
|
const addOrDropEnumValues = async (migration, up, enumName, values, options) => {
|
|
2538
|
-
const [schema, name] = getSchemaAndTableFromName(enumName);
|
|
2779
|
+
const [schema, name] = getSchemaAndTableFromName(migration.options, enumName);
|
|
2539
2780
|
const quotedName = quoteTable(schema, name);
|
|
2540
2781
|
const ast = {
|
|
2541
2782
|
type: "enumValues",
|
|
@@ -2571,7 +2812,7 @@ const addOrDropEnumValues = async (migration, up, enumName, values, options) =>
|
|
|
2571
2812
|
);
|
|
2572
2813
|
};
|
|
2573
2814
|
const changeEnumValues = async (migration, enumName, fromValues, toValues) => {
|
|
2574
|
-
const [schema, name] = getSchemaAndTableFromName(enumName);
|
|
2815
|
+
const [schema, name] = getSchemaAndTableFromName(migration.options, enumName);
|
|
2575
2816
|
if (!migration.up) {
|
|
2576
2817
|
const values = fromValues;
|
|
2577
2818
|
fromValues = toValues;
|
|
@@ -2594,7 +2835,8 @@ const changeEnumValues = async (migration, enumName, fromValues, toValues) => {
|
|
|
2594
2835
|
);
|
|
2595
2836
|
};
|
|
2596
2837
|
const recreateEnum = async (migration, { schema, name }, values, errorMessage) => {
|
|
2597
|
-
const
|
|
2838
|
+
const configSchema = migration.options.schema;
|
|
2839
|
+
const defaultSchema = (typeof configSchema === "function" ? configSchema() : void 0) ?? "public";
|
|
2598
2840
|
const quotedName = quoteTable(schema, name);
|
|
2599
2841
|
const relKinds = ["r", "m"];
|
|
2600
2842
|
const { rows: tables } = await migration.adapter.query(
|
|
@@ -2664,8 +2906,7 @@ ${migrationCode}`
|
|
|
2664
2906
|
);
|
|
2665
2907
|
config.logger?.log(`Created ${pqb.pathToLog(filePath)}`);
|
|
2666
2908
|
};
|
|
2667
|
-
const newMigration = async (config,
|
|
2668
|
-
if (!name) throw new Error("Migration name is missing");
|
|
2909
|
+
const newMigration = async (config, name) => {
|
|
2669
2910
|
const version = await makeFileVersion({}, config);
|
|
2670
2911
|
await writeMigrationFile(config, version, name, makeContent(name));
|
|
2671
2912
|
};
|
|
@@ -2721,16 +2962,9 @@ const fileNamesToChangeMigrationId = {
|
|
|
2721
2962
|
timestamp: ".rename-to-timestamp.json"
|
|
2722
2963
|
};
|
|
2723
2964
|
const fileNamesToChangeMigrationIdMap = Object.fromEntries(
|
|
2724
|
-
Object.entries(fileNamesToChangeMigrationId).map(([
|
|
2965
|
+
Object.entries(fileNamesToChangeMigrationId).map(([, name]) => [name, true])
|
|
2725
2966
|
);
|
|
2726
|
-
const changeIds = async (adapters, config,
|
|
2727
|
-
if (arg !== "serial" && arg !== "timestamp") {
|
|
2728
|
-
throw new Error(
|
|
2729
|
-
`Pass "serial" or "timestamp" argument to the "change-ids" command`
|
|
2730
|
-
);
|
|
2731
|
-
}
|
|
2732
|
-
let digits = digitsArg && parseInt(digitsArg);
|
|
2733
|
-
if (!digits || isNaN(digits)) digits = 4;
|
|
2967
|
+
const changeIds = async (adapters, config, { format, digits = 4 }) => {
|
|
2734
2968
|
const data = await getMigrations({}, config, true, false, (_, filePath) => {
|
|
2735
2969
|
const fileName = path.basename(filePath);
|
|
2736
2970
|
const match = fileName.match(/^(\d+)\D/);
|
|
@@ -2742,9 +2976,9 @@ const changeIds = async (adapters, config, [arg, digitsArg]) => {
|
|
|
2742
2976
|
return match[1];
|
|
2743
2977
|
});
|
|
2744
2978
|
if (data.renameTo) {
|
|
2745
|
-
if (
|
|
2979
|
+
if (format === "serial" && typeof data.renameTo.to === "object" && digits === data.renameTo.to.serial || format === "timestamp" && data.renameTo.to === "timestamp") {
|
|
2746
2980
|
config.logger?.log(
|
|
2747
|
-
config.migrations ? "`renameMigrations` setting is already set" : `${fileNamesToChangeMigrationId[
|
|
2981
|
+
config.migrations ? "`renameMigrations` setting is already set" : `${fileNamesToChangeMigrationId[format]} already exists`
|
|
2748
2982
|
);
|
|
2749
2983
|
return;
|
|
2750
2984
|
}
|
|
@@ -2757,15 +2991,15 @@ const changeIds = async (adapters, config, [arg, digitsArg]) => {
|
|
|
2757
2991
|
);
|
|
2758
2992
|
}
|
|
2759
2993
|
}
|
|
2760
|
-
const version =
|
|
2994
|
+
const version = format === "timestamp" ? parseInt(generateTimeStamp()) : 1;
|
|
2761
2995
|
const rename = Object.fromEntries(
|
|
2762
2996
|
data.migrations.map((item, i) => [path.basename(item.path), version + i])
|
|
2763
2997
|
);
|
|
2764
2998
|
if (config.migrations) {
|
|
2765
|
-
const to =
|
|
2999
|
+
const to = format === "timestamp" ? `'${format}'` : `{ serial: ${digits} }`;
|
|
2766
3000
|
config.logger?.log(
|
|
2767
3001
|
`Save the following settings into your rake-db config under the \`migrations\` setting, it will instruct rake-db to rename migration entries during the next deploy:
|
|
2768
|
-
${
|
|
3002
|
+
${format !== "serial" || digits !== 4 ? `
|
|
2769
3003
|
migrationId: ${to},` : ""}
|
|
2770
3004
|
renameMigrations: {
|
|
2771
3005
|
to: ${to},
|
|
@@ -2774,14 +3008,14 @@ renameMigrations: {
|
|
|
2774
3008
|
);
|
|
2775
3009
|
} else {
|
|
2776
3010
|
await fs.writeFile(
|
|
2777
|
-
path.join(config.migrationsPath, fileNamesToChangeMigrationId[
|
|
3011
|
+
path.join(config.migrationsPath, fileNamesToChangeMigrationId[format]),
|
|
2778
3012
|
JSON.stringify(rename, null, 2)
|
|
2779
3013
|
);
|
|
2780
3014
|
}
|
|
2781
3015
|
const values = data.migrations.map(
|
|
2782
3016
|
(item, i) => {
|
|
2783
3017
|
let newVersion = String(version + i);
|
|
2784
|
-
if (
|
|
3018
|
+
if (format === "serial") newVersion = newVersion.padStart(digits, "0");
|
|
2785
3019
|
const name = path.basename(item.path).slice(item.version.length + 1);
|
|
2786
3020
|
return [item.version, name, newVersion];
|
|
2787
3021
|
}
|
|
@@ -2818,9 +3052,9 @@ After setting \`renameMigrations\` (see above) and renaming the files, run the d
|
|
|
2818
3052
|
})
|
|
2819
3053
|
);
|
|
2820
3054
|
config.logger?.log(
|
|
2821
|
-
`Migration files were renamed, a config file ${fileNamesToChangeMigrationId[
|
|
3055
|
+
`Migration files were renamed, a config file ${fileNamesToChangeMigrationId[format]} for renaming migrations after deploy was created, and migrations in local db were renamed successfully.
|
|
2822
3056
|
|
|
2823
|
-
${
|
|
3057
|
+
${format === "timestamp" || digits !== 4 ? `Set \`migrationId\`: ${format === "timestamp" ? `'timestamp'` : `{ serial: ${digits} }`}` : `Remove \`migrationId\``} setting in the rake-db config`
|
|
2824
3058
|
);
|
|
2825
3059
|
};
|
|
2826
3060
|
const renameMigrationVersionsInDb = async (config, adapter, values) => {
|
|
@@ -2998,35 +3232,26 @@ const saveMigratedVersion = async (db, version, name, config) => {
|
|
|
2998
3232
|
[version, name]
|
|
2999
3233
|
);
|
|
3000
3234
|
};
|
|
3001
|
-
const
|
|
3002
|
-
const { schema } = getMigrationsSchemaAndTable(config);
|
|
3235
|
+
const createMigrationsSchemaAndTable = async (adapter, config) => {
|
|
3236
|
+
const { schema, table } = getMigrationsSchemaAndTable(config);
|
|
3003
3237
|
if (schema) {
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
config.logger?.log(`Created schema ${schema}`);
|
|
3007
|
-
} catch (err) {
|
|
3008
|
-
if (err.code !== "42P06") {
|
|
3009
|
-
throw err;
|
|
3010
|
-
}
|
|
3238
|
+
const res2 = await createSchema$1(adapter, schema);
|
|
3239
|
+
if (res2 === "done") {
|
|
3240
|
+
config.logger?.log(`Created schema "${schema}"`);
|
|
3011
3241
|
}
|
|
3012
3242
|
}
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3243
|
+
const res = await createTable$1(
|
|
3244
|
+
adapter,
|
|
3245
|
+
`${schema ? `"${schema}"."${table}"` : `"${table}"`} (version TEXT NOT NULL, name TEXT NOT NULL)`
|
|
3246
|
+
);
|
|
3247
|
+
if (res === "done") {
|
|
3248
|
+
config.logger?.log(
|
|
3249
|
+
`Created migration versions table ${schema ? `"${schema}".` : ""}"${table}"`
|
|
3018
3250
|
);
|
|
3019
|
-
config.logger?.log("Created versions table");
|
|
3020
|
-
} catch (err) {
|
|
3021
|
-
if (err.code === "42P07") {
|
|
3022
|
-
config.logger?.log("Versions table exists");
|
|
3023
|
-
} else {
|
|
3024
|
-
throw err;
|
|
3025
|
-
}
|
|
3026
3251
|
}
|
|
3027
3252
|
};
|
|
3028
|
-
const deleteMigratedVersion = async (
|
|
3029
|
-
const res = await
|
|
3253
|
+
const deleteMigratedVersion = async (adapter, version, name, config) => {
|
|
3254
|
+
const res = await adapter.silentArrays(
|
|
3030
3255
|
`DELETE FROM ${migrationsSchemaTableSql(
|
|
3031
3256
|
config
|
|
3032
3257
|
)} WHERE version = $1 AND name = $2`,
|
|
@@ -3116,91 +3341,76 @@ async function renameMigrations(config, trx, versions, renameTo) {
|
|
|
3116
3341
|
return updatedVersions;
|
|
3117
3342
|
}
|
|
3118
3343
|
|
|
3119
|
-
const transactionIfSingle = (
|
|
3120
|
-
return
|
|
3121
|
-
};
|
|
3122
|
-
function makeMigrateFn(up, fn) {
|
|
3123
|
-
return async (params) => {
|
|
3124
|
-
const ctx = params
|
|
3125
|
-
const set = await getMigrations(ctx,
|
|
3126
|
-
const count = params
|
|
3127
|
-
const force = params
|
|
3344
|
+
const transactionIfSingle = (adapter, config, fn) => {
|
|
3345
|
+
return !adapter.isInTransaction() && config.transaction === "single" ? transaction(adapter, fn) : fn(adapter);
|
|
3346
|
+
};
|
|
3347
|
+
function makeMigrateFn(up, defaultCount, fn) {
|
|
3348
|
+
return async (db, config, params) => {
|
|
3349
|
+
const ctx = params?.ctx || {};
|
|
3350
|
+
const set = await getMigrations(ctx, config, up);
|
|
3351
|
+
const count = params?.count ?? defaultCount;
|
|
3352
|
+
const force = params?.force ?? false;
|
|
3353
|
+
const adapter = getMaybeTransactionAdapter(db);
|
|
3128
3354
|
let migrations;
|
|
3129
3355
|
try {
|
|
3130
|
-
await transactionIfSingle(
|
|
3356
|
+
await transactionIfSingle(adapter, config, async (trx) => {
|
|
3131
3357
|
const versions = await getMigratedVersionsMap(
|
|
3132
3358
|
ctx,
|
|
3133
3359
|
trx,
|
|
3134
|
-
|
|
3360
|
+
config,
|
|
3135
3361
|
set.renameTo
|
|
3136
3362
|
);
|
|
3137
|
-
migrations = await fn(trx,
|
|
3363
|
+
migrations = await fn(trx, config, set, versions, count, force);
|
|
3138
3364
|
});
|
|
3139
3365
|
} catch (err) {
|
|
3140
3366
|
if (err instanceof NoMigrationsTableError) {
|
|
3141
|
-
await transactionIfSingle(
|
|
3142
|
-
await
|
|
3367
|
+
await transactionIfSingle(adapter, config, async (trx) => {
|
|
3368
|
+
await createMigrationsSchemaAndTable(trx, config);
|
|
3143
3369
|
const versions = await getMigratedVersionsMap(
|
|
3144
3370
|
ctx,
|
|
3145
3371
|
trx,
|
|
3146
|
-
|
|
3372
|
+
config,
|
|
3147
3373
|
set.renameTo
|
|
3148
3374
|
);
|
|
3149
|
-
migrations = await fn(
|
|
3150
|
-
trx,
|
|
3151
|
-
params.config,
|
|
3152
|
-
set,
|
|
3153
|
-
versions,
|
|
3154
|
-
count,
|
|
3155
|
-
force
|
|
3156
|
-
);
|
|
3375
|
+
migrations = await fn(trx, config, set, versions, count, force);
|
|
3157
3376
|
});
|
|
3158
3377
|
} else {
|
|
3159
3378
|
throw err;
|
|
3160
3379
|
}
|
|
3161
3380
|
}
|
|
3162
|
-
|
|
3163
|
-
adapter
|
|
3381
|
+
config.afterChangeCommit?.({
|
|
3382
|
+
adapter,
|
|
3164
3383
|
up,
|
|
3165
3384
|
migrations
|
|
3166
3385
|
});
|
|
3167
3386
|
};
|
|
3168
3387
|
}
|
|
3169
|
-
const makeMigrateCommand = (migrateFn, defaultCount) => {
|
|
3170
|
-
return async (adapters, config, args) => {
|
|
3171
|
-
const arg = args[0];
|
|
3172
|
-
let force = arg === "force";
|
|
3173
|
-
let count = defaultCount;
|
|
3174
|
-
if (arg === "force") {
|
|
3175
|
-
force = true;
|
|
3176
|
-
} else {
|
|
3177
|
-
force = false;
|
|
3178
|
-
const num = arg === "all" ? Infinity : parseInt(arg || "");
|
|
3179
|
-
if (!isNaN(num)) {
|
|
3180
|
-
count = num;
|
|
3181
|
-
}
|
|
3182
|
-
}
|
|
3183
|
-
for (const adapter of adapters) {
|
|
3184
|
-
await migrateFn({ ctx: {}, adapter, config, count, force });
|
|
3185
|
-
}
|
|
3186
|
-
};
|
|
3187
|
-
};
|
|
3188
3388
|
const migrate = makeMigrateFn(
|
|
3189
3389
|
true,
|
|
3390
|
+
Infinity,
|
|
3190
3391
|
(trx, config, set, versions, count, force) => migrateOrRollback(trx, config, set, versions, count, true, false, force)
|
|
3191
3392
|
);
|
|
3192
|
-
const migrateAndClose = async (params) => {
|
|
3193
|
-
|
|
3194
|
-
await params
|
|
3393
|
+
const migrateAndClose = async (db, config, params) => {
|
|
3394
|
+
const adapter = getMaybeTransactionAdapter(db);
|
|
3395
|
+
await migrate(adapter, config, params);
|
|
3396
|
+
await adapter.close();
|
|
3397
|
+
};
|
|
3398
|
+
const runMigration = async (db, migration) => {
|
|
3399
|
+
await ensureTransaction(db, async (trx) => {
|
|
3400
|
+
clearChanges();
|
|
3401
|
+
const changes = await getChanges({ load: migration });
|
|
3402
|
+
const config = changes[0]?.config;
|
|
3403
|
+
await applyMigration(trx, true, changes, config);
|
|
3404
|
+
});
|
|
3195
3405
|
};
|
|
3196
|
-
const migrateCommand = makeMigrateCommand(migrate, Infinity);
|
|
3197
3406
|
const rollback = makeMigrateFn(
|
|
3198
3407
|
false,
|
|
3408
|
+
1,
|
|
3199
3409
|
(trx, config, set, versions, count, force) => migrateOrRollback(trx, config, set, versions, count, false, false, force)
|
|
3200
3410
|
);
|
|
3201
|
-
const rollbackCommand = makeMigrateCommand(rollback, 1);
|
|
3202
3411
|
const redo = makeMigrateFn(
|
|
3203
3412
|
true,
|
|
3413
|
+
1,
|
|
3204
3414
|
async (trx, config, set, versions, count, force) => {
|
|
3205
3415
|
set.migrations.reverse();
|
|
3206
3416
|
await migrateOrRollback(trx, config, set, versions, count, false, true);
|
|
@@ -3218,7 +3428,6 @@ const redo = makeMigrateFn(
|
|
|
3218
3428
|
);
|
|
3219
3429
|
}
|
|
3220
3430
|
);
|
|
3221
|
-
const redoCommand = makeMigrateCommand(redo, 1);
|
|
3222
3431
|
const getDb = (adapter) => pqb.createDbWithAdapter({ adapter });
|
|
3223
3432
|
const migrateOrRollback = async (trx, config, set, versions, count, up, redo2, force, skipLock) => {
|
|
3224
3433
|
const { sequence, map: versionsMap } = versions;
|
|
@@ -3257,7 +3466,7 @@ const migrateOrRollback = async (trx, config, set, versions, count, up, redo2, f
|
|
|
3257
3466
|
}
|
|
3258
3467
|
let loggedAboutStarting = false;
|
|
3259
3468
|
let migrations;
|
|
3260
|
-
const migrationRunner = config.transaction === "single" ?
|
|
3469
|
+
const migrationRunner = trx.isInTransaction() || config.transaction === "single" ? applyMigration : runMigrationInOwnTransaction;
|
|
3261
3470
|
for (const file of set.migrations) {
|
|
3262
3471
|
if (up && versionsMap[file.version] || !up && !versionsMap[file.version]) {
|
|
3263
3472
|
continue;
|
|
@@ -3325,347 +3534,53 @@ const checkMigrationOrder = (config, set, { sequence, map }, force) => {
|
|
|
3325
3534
|
`Cannot migrate ${path.basename(
|
|
3326
3535
|
file.path
|
|
3327
3536
|
)} because the higher position ${map[versionToString(config, last)]} was already migrated.
|
|
3328
|
-
Run \`**db command** up force\` to rollback the above migrations and migrate all`
|
|
3329
|
-
);
|
|
3330
|
-
}
|
|
3331
|
-
return version;
|
|
3332
|
-
}
|
|
3333
|
-
}
|
|
3334
|
-
return;
|
|
3335
|
-
};
|
|
3336
|
-
const changeCache = {};
|
|
3337
|
-
const getChanges = async (file, config) => {
|
|
3338
|
-
clearChanges();
|
|
3339
|
-
let changes = file.path ? changeCache[file.path] : void 0;
|
|
3340
|
-
if (!changes) {
|
|
3341
|
-
const module = await file.load();
|
|
3342
|
-
const exported = module?.default && pqb.toArray(module.default);
|
|
3343
|
-
if (config?.forceDefaultExports && !exported) {
|
|
3344
|
-
throw new RakeDbError(
|
|
3345
|
-
`Missing a default export in ${file.path} migration`
|
|
3346
|
-
);
|
|
3347
|
-
}
|
|
3348
|
-
changes = exported || getCurrentChanges();
|
|
3349
|
-
if (file.path) changeCache[file.path] = changes;
|
|
3350
|
-
}
|
|
3351
|
-
return changes;
|
|
3352
|
-
};
|
|
3353
|
-
const runMigrationInOwnTransaction = (adapter, ...rest) => {
|
|
3354
|
-
return transaction(adapter, (trx) => runMigration(trx, ...rest));
|
|
3355
|
-
};
|
|
3356
|
-
const runMigration = async (trx, up, changes, config) => {
|
|
3357
|
-
const db = createMigrationInterface(trx, up, config);
|
|
3358
|
-
if (changes.length) {
|
|
3359
|
-
const from = up ? 0 : changes.length - 1;
|
|
3360
|
-
const to = up ? changes.length : -1;
|
|
3361
|
-
const step = up ? 1 : -1;
|
|
3362
|
-
for (let i = from; i !== to; i += step) {
|
|
3363
|
-
await changes[i].fn(db, up);
|
|
3364
|
-
}
|
|
3365
|
-
}
|
|
3366
|
-
return db.adapter;
|
|
3367
|
-
};
|
|
3368
|
-
const changeMigratedVersion = async (adapter, up, file, config) => {
|
|
3369
|
-
await (up ? saveMigratedVersion : deleteMigratedVersion)(
|
|
3370
|
-
adapter,
|
|
3371
|
-
file.version,
|
|
3372
|
-
path.basename(file.path).slice(file.version.length + 1),
|
|
3373
|
-
config
|
|
3374
|
-
);
|
|
3375
|
-
};
|
|
3376
|
-
|
|
3377
|
-
const ESC = "\x1B";
|
|
3378
|
-
const CSI = `${ESC}[`;
|
|
3379
|
-
const cursorShow = `${CSI}?25h`;
|
|
3380
|
-
const cursorHide = `${CSI}?25l`;
|
|
3381
|
-
const { stdin, stdout } = process;
|
|
3382
|
-
const visibleChars = (s) => s.replace(
|
|
3383
|
-
// eslint-disable-next-line no-control-regex
|
|
3384
|
-
/[\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,
|
|
3385
|
-
""
|
|
3386
|
-
).length;
|
|
3387
|
-
const clear = (text) => {
|
|
3388
|
-
const rows = text.split(/\r?\n/).reduce(
|
|
3389
|
-
(rows2, line) => rows2 + 1 + Math.floor(Math.max(visibleChars(line) - 1, 0) / stdout.columns),
|
|
3390
|
-
0
|
|
3391
|
-
);
|
|
3392
|
-
let clear2 = "";
|
|
3393
|
-
for (let i = 0; i < rows; i++) {
|
|
3394
|
-
clear2 += `${CSI}2K`;
|
|
3395
|
-
if (i < rows - 1) {
|
|
3396
|
-
clear2 += `${CSI}${i < rows - 1 ? "1A" : "G"}`;
|
|
3397
|
-
}
|
|
3398
|
-
}
|
|
3399
|
-
return clear2;
|
|
3400
|
-
};
|
|
3401
|
-
const prompt = async ({
|
|
3402
|
-
render,
|
|
3403
|
-
onKeyPress,
|
|
3404
|
-
validate,
|
|
3405
|
-
value,
|
|
3406
|
-
cursor: showCursor
|
|
3407
|
-
}) => {
|
|
3408
|
-
stdin.resume();
|
|
3409
|
-
if (stdin.isTTY) stdin.setRawMode(true);
|
|
3410
|
-
stdin.setEncoding("utf-8");
|
|
3411
|
-
if (!showCursor) stdout.write(cursorHide);
|
|
3412
|
-
return new Promise((res) => {
|
|
3413
|
-
let prevText;
|
|
3414
|
-
const ctx = {
|
|
3415
|
-
value,
|
|
3416
|
-
submitted: false,
|
|
3417
|
-
render() {
|
|
3418
|
-
let text = (ctx.submitted ? pqb.colors.greenBold("\u2714") : pqb.colors.yellowBold("?")) + " " + render(ctx);
|
|
3419
|
-
if (ctx.submitted) text += "\n";
|
|
3420
|
-
stdout.write(prevText ? clear(prevText) + "\r" + text : text);
|
|
3421
|
-
prevText = text;
|
|
3422
|
-
},
|
|
3423
|
-
submit(value2) {
|
|
3424
|
-
if (value2 !== void 0) ctx.value = value2;
|
|
3425
|
-
if (ctx.value === void 0 || validate && !validate?.(ctx)) return;
|
|
3426
|
-
ctx.submitted = true;
|
|
3427
|
-
ctx.render();
|
|
3428
|
-
close();
|
|
3429
|
-
res(ctx.value);
|
|
3430
|
-
}
|
|
3431
|
-
};
|
|
3432
|
-
const close = () => {
|
|
3433
|
-
if (!showCursor) stdout.write(cursorShow);
|
|
3434
|
-
if (stdin.isTTY) stdin.setRawMode(false);
|
|
3435
|
-
stdin.off("data", keypress);
|
|
3436
|
-
stdin.pause();
|
|
3437
|
-
};
|
|
3438
|
-
const keypress = (s) => {
|
|
3439
|
-
if (s === "" || s === "") {
|
|
3440
|
-
close?.();
|
|
3441
|
-
process.exit(0);
|
|
3442
|
-
}
|
|
3443
|
-
if (s === "\r" || s === "\n" || s === "\r\n") {
|
|
3444
|
-
ctx.submit();
|
|
3445
|
-
} else {
|
|
3446
|
-
onKeyPress(ctx, s);
|
|
3447
|
-
}
|
|
3448
|
-
};
|
|
3449
|
-
stdin.on("data", keypress);
|
|
3450
|
-
ctx.render();
|
|
3451
|
-
});
|
|
3452
|
-
};
|
|
3453
|
-
const defaultActive = (s) => `${pqb.colors.blueBold("\u276F")} ${s}`;
|
|
3454
|
-
const defaultInactive = (s) => ` ${s}`;
|
|
3455
|
-
const promptSelect = ({
|
|
3456
|
-
message,
|
|
3457
|
-
options,
|
|
3458
|
-
active = defaultActive,
|
|
3459
|
-
inactive = defaultInactive
|
|
3460
|
-
}) => prompt({
|
|
3461
|
-
value: 0,
|
|
3462
|
-
render(ctx) {
|
|
3463
|
-
let text = `${message} ${pqb.colors.pale(
|
|
3464
|
-
"Use arrows or jk. Press enter to submit."
|
|
3465
|
-
)}
|
|
3466
|
-
`;
|
|
3467
|
-
for (let i = 0; i < options.length; i++) {
|
|
3468
|
-
text += (ctx.value === i ? active : inactive)(options[i]) + "\n";
|
|
3469
|
-
}
|
|
3470
|
-
return text;
|
|
3471
|
-
},
|
|
3472
|
-
onKeyPress(ctx, s) {
|
|
3473
|
-
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;
|
|
3474
|
-
ctx.render();
|
|
3475
|
-
}
|
|
3476
|
-
});
|
|
3477
|
-
const promptConfirm = ({
|
|
3478
|
-
message
|
|
3479
|
-
}) => prompt({
|
|
3480
|
-
value: true,
|
|
3481
|
-
render(ctx) {
|
|
3482
|
-
return `${pqb.colors.bright(message)}
|
|
3483
|
-
${ctx.submitted ? `> ${ctx.value ? pqb.colors.greenBold("Yes") : pqb.colors.yellowBold("No")}` : pqb.colors.pale(`> (Y/n)`)}
|
|
3484
|
-
`;
|
|
3485
|
-
},
|
|
3486
|
-
onKeyPress(ctx, s) {
|
|
3487
|
-
let ok;
|
|
3488
|
-
if (s === "y" || s === "Y") ok = true;
|
|
3489
|
-
else if (s === "n" || s === "N") ok = false;
|
|
3490
|
-
if (ok !== void 0) {
|
|
3491
|
-
ctx.submit(ok);
|
|
3492
|
-
}
|
|
3493
|
-
}
|
|
3494
|
-
});
|
|
3495
|
-
const promptText = ({
|
|
3496
|
-
message,
|
|
3497
|
-
default: def = "",
|
|
3498
|
-
password,
|
|
3499
|
-
min
|
|
3500
|
-
}) => {
|
|
3501
|
-
let showDefault = true;
|
|
3502
|
-
let x = 0;
|
|
3503
|
-
const renderValue = (ctx) => password ? "*".repeat(ctx.value.length) : ctx.value;
|
|
3504
|
-
return prompt({
|
|
3505
|
-
value: def,
|
|
3506
|
-
cursor: true,
|
|
3507
|
-
validate: (ctx) => !min || ctx.value.length >= min,
|
|
3508
|
-
render(ctx) {
|
|
3509
|
-
let text = `${pqb.colors.bright(message)}
|
|
3510
|
-
> ${ctx.submitted ? renderValue(ctx) : showDefault ? pqb.colors.pale(def) + "\b".repeat(def.length) : ctx.value}`;
|
|
3511
|
-
if (ctx.submitted) text += "\n";
|
|
3512
|
-
return text;
|
|
3513
|
-
},
|
|
3514
|
-
onKeyPress(ctx, s) {
|
|
3515
|
-
let value = showDefault ? "" : ctx.value;
|
|
3516
|
-
if (s === "\x1B[D" && x > 0) {
|
|
3517
|
-
x--;
|
|
3518
|
-
stdout.write("\b");
|
|
3519
|
-
} else if (s === "\x1B[C" && x < value.length) {
|
|
3520
|
-
stdout.write(value[x]);
|
|
3521
|
-
x++;
|
|
3522
|
-
}
|
|
3523
|
-
if (s !== "\x7F" && s !== "\x1B[3~" && !visibleChars(s)) return;
|
|
3524
|
-
if (showDefault) {
|
|
3525
|
-
showDefault = false;
|
|
3526
|
-
stdout.write(" ".repeat(def.length) + "\b".repeat(def.length));
|
|
3527
|
-
}
|
|
3528
|
-
const prev = value;
|
|
3529
|
-
const prevX = x;
|
|
3530
|
-
if (s === "\x7F") {
|
|
3531
|
-
if (x > 0) {
|
|
3532
|
-
value = value.slice(0, x - 1) + value.slice(x);
|
|
3533
|
-
x--;
|
|
3534
|
-
}
|
|
3535
|
-
} else if (s === "\x1B[3~") {
|
|
3536
|
-
if (x < value.length) {
|
|
3537
|
-
value = value.slice(0, x) + value.slice(x + 1);
|
|
3538
|
-
}
|
|
3539
|
-
} else {
|
|
3540
|
-
value = value.slice(0, x) + s + value.slice(x);
|
|
3541
|
-
x++;
|
|
3542
|
-
}
|
|
3543
|
-
ctx.value = value;
|
|
3544
|
-
const spaces = prev.length - value.length;
|
|
3545
|
-
stdout.write(
|
|
3546
|
-
"\b".repeat(prevX) + renderValue(ctx) + (spaces > 0 ? " ".repeat(spaces) + "\b".repeat(spaces) : "") + "\b".repeat(value.length - x)
|
|
3547
|
-
);
|
|
3548
|
-
}
|
|
3549
|
-
});
|
|
3550
|
-
};
|
|
3551
|
-
|
|
3552
|
-
const execute = async (adapter, sql) => {
|
|
3553
|
-
try {
|
|
3554
|
-
await adapter.query(sql);
|
|
3555
|
-
return "ok";
|
|
3556
|
-
} catch (error) {
|
|
3557
|
-
const err = error;
|
|
3558
|
-
if (typeof err.message === "string" && err.message.includes("sslmode=require")) {
|
|
3559
|
-
return "ssl required";
|
|
3560
|
-
}
|
|
3561
|
-
if (err.code === "42P04" || err.code === "3D000") {
|
|
3562
|
-
return "already";
|
|
3563
|
-
} else if (err.code === "42501" || typeof err.message === "string" && err.message.includes("password authentication failed")) {
|
|
3564
|
-
return "forbidden";
|
|
3565
|
-
} else {
|
|
3566
|
-
return { error };
|
|
3567
|
-
}
|
|
3568
|
-
} finally {
|
|
3569
|
-
await adapter.close();
|
|
3570
|
-
}
|
|
3571
|
-
};
|
|
3572
|
-
const createOrDrop = async (adapter, adminAdapter, config, args) => {
|
|
3573
|
-
const params = {
|
|
3574
|
-
database: adapter.getDatabase(),
|
|
3575
|
-
user: adapter.getUser()
|
|
3576
|
-
};
|
|
3577
|
-
const result = await execute(
|
|
3578
|
-
adminAdapter.reconfigure({ database: "postgres" }),
|
|
3579
|
-
args.sql(params)
|
|
3580
|
-
);
|
|
3581
|
-
if (result === "ok") {
|
|
3582
|
-
config.logger?.log(args.successMessage(params));
|
|
3583
|
-
} else if (result === "already") {
|
|
3584
|
-
config.logger?.log(args.alreadyMessage(params));
|
|
3585
|
-
} else if (result === "ssl required") {
|
|
3586
|
-
config.logger?.log(
|
|
3587
|
-
"SSL is required: append ?ssl=true to the database url string"
|
|
3588
|
-
);
|
|
3589
|
-
return;
|
|
3590
|
-
} else if (result === "forbidden") {
|
|
3591
|
-
let message = `Permission denied to ${args.create ? "create" : "drop"} database.`;
|
|
3592
|
-
const host = adminAdapter.getHost();
|
|
3593
|
-
const isLocal = host === "localhost";
|
|
3594
|
-
if (!isLocal) {
|
|
3595
|
-
message += `
|
|
3596
|
-
Don't use this command for database service providers, only for a local db.`;
|
|
3597
|
-
}
|
|
3598
|
-
config.logger?.log(message);
|
|
3599
|
-
const params2 = await askForAdminCredentials(args.create);
|
|
3600
|
-
if (!params2) return;
|
|
3601
|
-
await createOrDrop(adapter, adminAdapter.reconfigure(params2), config, args);
|
|
3602
|
-
return;
|
|
3603
|
-
} else {
|
|
3604
|
-
throw result.error;
|
|
3605
|
-
}
|
|
3606
|
-
if (!args.create) return;
|
|
3607
|
-
const newlyConnectedAdapter = adapter.reconfigure({});
|
|
3608
|
-
await createMigrationsTable(newlyConnectedAdapter, config);
|
|
3609
|
-
await newlyConnectedAdapter.close();
|
|
3610
|
-
};
|
|
3611
|
-
const createDb = async (adapters, config) => {
|
|
3612
|
-
for (const adapter of adapters) {
|
|
3613
|
-
await createOrDrop(adapter, adapter, config, {
|
|
3614
|
-
sql({ database, user }) {
|
|
3615
|
-
return `CREATE DATABASE "${database}"${user ? ` OWNER "${user}"` : ""}`;
|
|
3616
|
-
},
|
|
3617
|
-
successMessage({ database }) {
|
|
3618
|
-
return `Database ${database} successfully created`;
|
|
3619
|
-
},
|
|
3620
|
-
alreadyMessage({ database }) {
|
|
3621
|
-
return `Database ${database} already exists`;
|
|
3622
|
-
},
|
|
3623
|
-
create: true
|
|
3624
|
-
});
|
|
3625
|
-
}
|
|
3626
|
-
};
|
|
3627
|
-
const dropDb = async (adapters, config) => {
|
|
3628
|
-
for (const adapter of adapters) {
|
|
3629
|
-
await createOrDrop(adapter, adapter, config, {
|
|
3630
|
-
sql({ database }) {
|
|
3631
|
-
return `DROP DATABASE "${database}"`;
|
|
3632
|
-
},
|
|
3633
|
-
successMessage({ database }) {
|
|
3634
|
-
return `Database ${database} was successfully dropped`;
|
|
3635
|
-
},
|
|
3636
|
-
alreadyMessage({ database }) {
|
|
3637
|
-
return `Database ${database} does not exist`;
|
|
3537
|
+
Run \`**db command** up force\` to rollback the above migrations and migrate all`
|
|
3538
|
+
);
|
|
3638
3539
|
}
|
|
3639
|
-
|
|
3540
|
+
return version;
|
|
3541
|
+
}
|
|
3640
3542
|
}
|
|
3543
|
+
return;
|
|
3641
3544
|
};
|
|
3642
|
-
const
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3545
|
+
const changeCache = {};
|
|
3546
|
+
const getChanges = async (file, config) => {
|
|
3547
|
+
clearChanges();
|
|
3548
|
+
let changes = file.path ? changeCache[file.path] : void 0;
|
|
3549
|
+
if (!changes) {
|
|
3550
|
+
const module = await file.load();
|
|
3551
|
+
const exported = module?.default && pqb.toArray(module.default);
|
|
3552
|
+
if (config?.forceDefaultExports && !exported) {
|
|
3553
|
+
throw new RakeDbError(
|
|
3554
|
+
`Missing a default export in ${file.path} migration`
|
|
3555
|
+
);
|
|
3556
|
+
}
|
|
3557
|
+
changes = exported || getCurrentChanges();
|
|
3558
|
+
if (file.path) changeCache[file.path] = changes;
|
|
3647
3559
|
}
|
|
3560
|
+
return changes;
|
|
3648
3561
|
};
|
|
3649
|
-
const
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3562
|
+
const runMigrationInOwnTransaction = (adapter, ...rest) => {
|
|
3563
|
+
return transaction(adapter, (trx) => applyMigration(trx, ...rest));
|
|
3564
|
+
};
|
|
3565
|
+
const applyMigration = async (trx, up, changes, config) => {
|
|
3566
|
+
const db = createMigrationInterface(trx, up, config);
|
|
3567
|
+
if (changes.length) {
|
|
3568
|
+
const from = up ? 0 : changes.length - 1;
|
|
3569
|
+
const to = up ? changes.length : -1;
|
|
3570
|
+
const step = up ? 1 : -1;
|
|
3571
|
+
for (let i = from; i !== to; i += step) {
|
|
3572
|
+
await changes[i].fn(db, up);
|
|
3573
|
+
}
|
|
3655
3574
|
}
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
return {
|
|
3666
|
-
user,
|
|
3667
|
-
password: password || void 0
|
|
3668
|
-
};
|
|
3575
|
+
return db.adapter;
|
|
3576
|
+
};
|
|
3577
|
+
const changeMigratedVersion = async (adapter, up, file, config) => {
|
|
3578
|
+
await (up ? saveMigratedVersion : deleteMigratedVersion)(
|
|
3579
|
+
adapter,
|
|
3580
|
+
file.version,
|
|
3581
|
+
path.basename(file.path).slice(file.version.length + 1),
|
|
3582
|
+
config
|
|
3583
|
+
);
|
|
3669
3584
|
};
|
|
3670
3585
|
|
|
3671
3586
|
const runRecurrentMigrations = async (adapters, config) => {
|
|
@@ -3706,6 +3621,131 @@ const readdirRecursive = async (dirPath, cb) => {
|
|
|
3706
3621
|
);
|
|
3707
3622
|
};
|
|
3708
3623
|
|
|
3624
|
+
const createDatabaseCommand = (adapters, config, dontClose) => createOrDropDatabase("create", adapters, config, dontClose);
|
|
3625
|
+
const dropDatabaseCommand = (adapters, config) => createOrDropDatabase("drop", adapters, config);
|
|
3626
|
+
const createOrDropDatabase = async (action, adapters, config, dontClose) => {
|
|
3627
|
+
const fn = action === "create" ? createDatabase : dropDatabase;
|
|
3628
|
+
for (const adapter of adapters) {
|
|
3629
|
+
const database = adapter.getDatabase();
|
|
3630
|
+
const owner = adapter.getUser();
|
|
3631
|
+
const res = await run(
|
|
3632
|
+
adapter.reconfigure({ database: "postgres" }),
|
|
3633
|
+
config,
|
|
3634
|
+
{
|
|
3635
|
+
command: (adapter2) => fn(adapter2, {
|
|
3636
|
+
database,
|
|
3637
|
+
owner
|
|
3638
|
+
}),
|
|
3639
|
+
doneMessage: () => `Database ${database} successfully ${action === "create" ? "created" : "dropped"}`,
|
|
3640
|
+
alreadyMessage: () => `Database ${database} ${action === "create" ? "already exists" : "does not exist"}`,
|
|
3641
|
+
deniedMessage: () => `Permission denied to ${action} database.`,
|
|
3642
|
+
askAdminCreds: () => askForAdminCredentials(action === "create")
|
|
3643
|
+
}
|
|
3644
|
+
);
|
|
3645
|
+
if (!res) continue;
|
|
3646
|
+
if (action === "create") {
|
|
3647
|
+
await adapter.transaction(void 0, async (tx) => {
|
|
3648
|
+
if (config.schema) {
|
|
3649
|
+
const quoted = `"${config.schema}"`;
|
|
3650
|
+
const res2 = await createSchema$1(tx, quoted);
|
|
3651
|
+
if (res2 === "done") {
|
|
3652
|
+
config.logger?.log(`Created schema ${quoted}`);
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
await createMigrationsSchemaAndTable(tx, config);
|
|
3656
|
+
});
|
|
3657
|
+
if (!dontClose) {
|
|
3658
|
+
await adapter.close();
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
}
|
|
3662
|
+
};
|
|
3663
|
+
const resetDatabaseCommand = async (adapters, config) => {
|
|
3664
|
+
await createOrDropDatabase("create", adapters, config);
|
|
3665
|
+
await createOrDropDatabase("drop", adapters, config, true);
|
|
3666
|
+
for (const adapter of adapters) {
|
|
3667
|
+
await migrate(adapter, config);
|
|
3668
|
+
}
|
|
3669
|
+
if (config.recurrentPath) {
|
|
3670
|
+
await runRecurrentMigrations(adapters, config);
|
|
3671
|
+
}
|
|
3672
|
+
await Promise.all(adapters.map((adapter) => adapter.close()));
|
|
3673
|
+
};
|
|
3674
|
+
const run = async (adapter, config, params) => {
|
|
3675
|
+
try {
|
|
3676
|
+
const res = await params.command(adapter);
|
|
3677
|
+
config.logger?.log(
|
|
3678
|
+
res === "done" ? params.doneMessage() : params.alreadyMessage()
|
|
3679
|
+
);
|
|
3680
|
+
await adapter.close();
|
|
3681
|
+
return true;
|
|
3682
|
+
} catch (err) {
|
|
3683
|
+
if (err instanceof CreateOrDropError) {
|
|
3684
|
+
if (err.status === "ssl-required") {
|
|
3685
|
+
config.logger?.log(
|
|
3686
|
+
"SSL is required: append ?ssl=true to the database url string"
|
|
3687
|
+
);
|
|
3688
|
+
return false;
|
|
3689
|
+
}
|
|
3690
|
+
if (err.status === "forbidden" || err.status === "auth-failed") {
|
|
3691
|
+
let message = params.deniedMessage();
|
|
3692
|
+
const host = adapter.getHost();
|
|
3693
|
+
const isLocal = host === "localhost";
|
|
3694
|
+
if (!isLocal) {
|
|
3695
|
+
message += `
|
|
3696
|
+
Don't use this command for database service providers, only for a local db.`;
|
|
3697
|
+
}
|
|
3698
|
+
config.logger?.log(message);
|
|
3699
|
+
const creds = await params.askAdminCreds();
|
|
3700
|
+
if (!creds) return false;
|
|
3701
|
+
return run(adapter.reconfigure(creds), config, params);
|
|
3702
|
+
}
|
|
3703
|
+
}
|
|
3704
|
+
throw err;
|
|
3705
|
+
}
|
|
3706
|
+
};
|
|
3707
|
+
const askForAdminCredentials = async (create) => {
|
|
3708
|
+
const ok = await promptConfirm({
|
|
3709
|
+
message: `Would you like to share admin credentials to ${create ? "create" : "drop"} a database?`
|
|
3710
|
+
});
|
|
3711
|
+
if (!ok) {
|
|
3712
|
+
return;
|
|
3713
|
+
}
|
|
3714
|
+
const user = await promptText({
|
|
3715
|
+
message: "Enter admin user:",
|
|
3716
|
+
default: "postgres",
|
|
3717
|
+
min: 1
|
|
3718
|
+
});
|
|
3719
|
+
const password = await promptText({
|
|
3720
|
+
message: "Enter admin password:",
|
|
3721
|
+
password: true
|
|
3722
|
+
});
|
|
3723
|
+
return {
|
|
3724
|
+
user,
|
|
3725
|
+
password: password || void 0
|
|
3726
|
+
};
|
|
3727
|
+
};
|
|
3728
|
+
|
|
3729
|
+
const makeMigrateOrRollback = (fn) => async (adapters, config, args) => {
|
|
3730
|
+
const arg = args[0];
|
|
3731
|
+
let force;
|
|
3732
|
+
let count;
|
|
3733
|
+
if (arg === "force") {
|
|
3734
|
+
force = true;
|
|
3735
|
+
} else {
|
|
3736
|
+
const num = arg === "all" ? Infinity : parseInt(arg || "");
|
|
3737
|
+
if (!isNaN(num)) {
|
|
3738
|
+
count = num;
|
|
3739
|
+
}
|
|
3740
|
+
}
|
|
3741
|
+
for (const adapter of adapters) {
|
|
3742
|
+
await fn(adapter, config, { ctx: {}, count, force });
|
|
3743
|
+
}
|
|
3744
|
+
};
|
|
3745
|
+
const migrateCommand = makeMigrateOrRollback(migrate);
|
|
3746
|
+
const rollbackCommand = makeMigrateOrRollback(rollback);
|
|
3747
|
+
const redoCommand = makeMigrateOrRollback(redo);
|
|
3748
|
+
|
|
3709
3749
|
const astToGenerateItems = (config, asts, currentSchema) => {
|
|
3710
3750
|
return asts.map((ast) => astToGenerateItem(config, ast, currentSchema));
|
|
3711
3751
|
};
|
|
@@ -3717,7 +3757,10 @@ const astToGenerateItem = (config, ast, currentSchema) => {
|
|
|
3717
3757
|
const resolveType = (type) => {
|
|
3718
3758
|
let dep = typeSchemaCache.get(type);
|
|
3719
3759
|
if (!dep) {
|
|
3720
|
-
const [schema = currentSchema, name] = getSchemaAndTableFromName(
|
|
3760
|
+
const [schema = currentSchema, name] = getSchemaAndTableFromName(
|
|
3761
|
+
config,
|
|
3762
|
+
type
|
|
3763
|
+
);
|
|
3721
3764
|
dep = `${schema}.${name}`;
|
|
3722
3765
|
typeSchemaCache.set(type, dep);
|
|
3723
3766
|
}
|
|
@@ -3907,7 +3950,10 @@ const analyzeTableColumns = (config, currentSchema, schema, table, deps, resolve
|
|
|
3907
3950
|
config.snakeCase
|
|
3908
3951
|
)
|
|
3909
3952
|
);
|
|
3910
|
-
const [s = currentSchema, t] = getForeignKeyTable(
|
|
3953
|
+
const [s = currentSchema, t] = getForeignKeyTable(
|
|
3954
|
+
config,
|
|
3955
|
+
fkey.fnOrTable
|
|
3956
|
+
);
|
|
3911
3957
|
const foreignTable = `${s}.${t}`;
|
|
3912
3958
|
if (foreignTable !== table) {
|
|
3913
3959
|
deps.push(foreignTable);
|
|
@@ -3952,6 +3998,7 @@ const analyzeTableData = (config, currentSchema, schema, table, keys, deps, data
|
|
|
3952
3998
|
);
|
|
3953
3999
|
if (constraint.references) {
|
|
3954
4000
|
const [s = currentSchema, t] = getForeignKeyTable(
|
|
4001
|
+
config,
|
|
3955
4002
|
constraint.references.fnOrTable
|
|
3956
4003
|
);
|
|
3957
4004
|
deps.push(`${s}.${t}`);
|
|
@@ -5413,36 +5460,239 @@ const checkIfIsOuterRecursiveFkey = (data, table, references) => {
|
|
|
5413
5460
|
break;
|
|
5414
5461
|
}
|
|
5415
5462
|
}
|
|
5416
|
-
return false;
|
|
5417
|
-
};
|
|
5463
|
+
return false;
|
|
5464
|
+
};
|
|
5465
|
+
|
|
5466
|
+
const pullDbStructure = async (adapter, config) => {
|
|
5467
|
+
const currentSchema = adapter.searchPath || "public";
|
|
5468
|
+
const ctx = makeStructureToAstCtx(config, currentSchema);
|
|
5469
|
+
const ast = await structureToAst(ctx, adapter, config);
|
|
5470
|
+
const result = astToMigration(currentSchema, config, ast);
|
|
5471
|
+
if (!result) return;
|
|
5472
|
+
const version = await makeFileVersion({}, config);
|
|
5473
|
+
await writeMigrationFile(config, version, "pull", result);
|
|
5474
|
+
const silentQueries = Object.assign(adapter, {
|
|
5475
|
+
silentQuery: adapter.query,
|
|
5476
|
+
silentArrays: adapter.arrays
|
|
5477
|
+
});
|
|
5478
|
+
await saveMigratedVersion(silentQueries, version, "pull", config);
|
|
5479
|
+
const unsupportedEntries = Object.entries(ctx.unsupportedTypes);
|
|
5480
|
+
const len = unsupportedEntries.length;
|
|
5481
|
+
if (len) {
|
|
5482
|
+
let count = 0;
|
|
5483
|
+
config.logger?.warn(
|
|
5484
|
+
`Found unsupported types:
|
|
5485
|
+
${unsupportedEntries.map(([type, columns]) => {
|
|
5486
|
+
count += columns.length;
|
|
5487
|
+
return `- ${type} is used for column${columns.length > 1 ? "s" : ""} ${columns.join(", ")}`;
|
|
5488
|
+
}).join("\n")}
|
|
5489
|
+
Append \`as\` method manually to ${count > 1 ? "these" : "this"} column${count > 1 ? "s" : ""} to treat ${count > 1 ? "them" : "it"} as other column type`
|
|
5490
|
+
);
|
|
5491
|
+
}
|
|
5492
|
+
config.logger?.log("Database pulled successfully");
|
|
5493
|
+
};
|
|
5494
|
+
|
|
5495
|
+
const migrationConfigDefaults = {
|
|
5496
|
+
schemaConfig: pqb.defaultSchemaConfig,
|
|
5497
|
+
migrationsPath: path.join("src", "db", "migrations"),
|
|
5498
|
+
migrationId: { serial: 4 },
|
|
5499
|
+
migrationsTable: "schemaMigrations",
|
|
5500
|
+
snakeCase: false,
|
|
5501
|
+
commands: {},
|
|
5502
|
+
log: true,
|
|
5503
|
+
logger: console,
|
|
5504
|
+
import() {
|
|
5505
|
+
throw new Error(
|
|
5506
|
+
"Add `import: (path) => import(path),` setting to `rakeDb` config"
|
|
5507
|
+
);
|
|
5508
|
+
}
|
|
5509
|
+
};
|
|
5510
|
+
const ensureMigrationsPath = (config) => {
|
|
5511
|
+
if (!config.migrationsPath) {
|
|
5512
|
+
config.migrationsPath = migrationConfigDefaults.migrationsPath;
|
|
5513
|
+
}
|
|
5514
|
+
if (!path.isAbsolute(config.migrationsPath)) {
|
|
5515
|
+
config.migrationsPath = path.resolve(
|
|
5516
|
+
config.basePath,
|
|
5517
|
+
config.migrationsPath
|
|
5518
|
+
);
|
|
5519
|
+
}
|
|
5520
|
+
return config;
|
|
5521
|
+
};
|
|
5522
|
+
const ensureBasePathAndDbScript = (config, intermediateCallers2 = 0) => {
|
|
5523
|
+
if (config.basePath && config.dbScript) return config;
|
|
5524
|
+
let filePath = pqb.getStackTrace()?.[3 + intermediateCallers2]?.getFileName();
|
|
5525
|
+
if (!filePath) {
|
|
5526
|
+
throw new Error(
|
|
5527
|
+
"Failed to determine path to db script. Please set basePath option of rakeDb"
|
|
5528
|
+
);
|
|
5529
|
+
}
|
|
5530
|
+
if (filePath.startsWith("file://")) {
|
|
5531
|
+
filePath = node_url.fileURLToPath(filePath);
|
|
5532
|
+
}
|
|
5533
|
+
const ext = path.extname(filePath);
|
|
5534
|
+
if (ext !== ".ts" && ext !== ".js" && ext !== ".mjs") {
|
|
5535
|
+
throw new Error(
|
|
5536
|
+
`Add a .ts suffix to the "${path.basename(filePath)}" when calling it`
|
|
5537
|
+
);
|
|
5538
|
+
}
|
|
5539
|
+
config.basePath = path.dirname(filePath);
|
|
5540
|
+
config.dbScript = path.basename(filePath);
|
|
5541
|
+
return config;
|
|
5542
|
+
};
|
|
5543
|
+
let intermediateCallers = 0;
|
|
5544
|
+
const incrementIntermediateCaller = () => {
|
|
5545
|
+
intermediateCallers++;
|
|
5546
|
+
};
|
|
5547
|
+
const makeRakeDbConfig = (config, args) => {
|
|
5548
|
+
const ic = intermediateCallers;
|
|
5549
|
+
intermediateCallers = 0;
|
|
5550
|
+
const result = {
|
|
5551
|
+
...migrationConfigDefaults,
|
|
5552
|
+
...config,
|
|
5553
|
+
__rakeDbConfig: true
|
|
5554
|
+
};
|
|
5555
|
+
if (!result.log) {
|
|
5556
|
+
delete result.logger;
|
|
5557
|
+
}
|
|
5558
|
+
ensureBasePathAndDbScript(result, ic);
|
|
5559
|
+
ensureMigrationsPath(result);
|
|
5560
|
+
if (!result.recurrentPath) {
|
|
5561
|
+
result.recurrentPath = path.join(
|
|
5562
|
+
result.migrationsPath,
|
|
5563
|
+
"recurrent"
|
|
5564
|
+
);
|
|
5565
|
+
}
|
|
5566
|
+
if ("recurrentPath" in result && !path.isAbsolute(result.recurrentPath)) {
|
|
5567
|
+
result.recurrentPath = path.resolve(result.basePath, result.recurrentPath);
|
|
5568
|
+
}
|
|
5569
|
+
if ("baseTable" in config && config.baseTable) {
|
|
5570
|
+
const { types, snakeCase, language } = config.baseTable.prototype;
|
|
5571
|
+
result.columnTypes = types || pqb.makeColumnTypes(pqb.defaultSchemaConfig);
|
|
5572
|
+
if (snakeCase) result.snakeCase = true;
|
|
5573
|
+
if (language) result.language = language;
|
|
5574
|
+
} else {
|
|
5575
|
+
const ct = "columnTypes" in config && config.columnTypes;
|
|
5576
|
+
result.columnTypes = (typeof ct === "function" ? ct(
|
|
5577
|
+
pqb.makeColumnTypes(pqb.defaultSchemaConfig)
|
|
5578
|
+
) : ct) || pqb.makeColumnTypes(pqb.defaultSchemaConfig);
|
|
5579
|
+
}
|
|
5580
|
+
if (config.migrationId === "serial") {
|
|
5581
|
+
result.migrationId = { serial: 4 };
|
|
5582
|
+
}
|
|
5583
|
+
const transaction = getCliParam(args, "transaction");
|
|
5584
|
+
if (transaction) {
|
|
5585
|
+
if (transaction !== "single" && transaction !== "per-migration") {
|
|
5586
|
+
throw new Error(
|
|
5587
|
+
`Unsupported transaction param ${transaction}, expected single or per-migration`
|
|
5588
|
+
);
|
|
5589
|
+
}
|
|
5590
|
+
result.transaction = transaction;
|
|
5591
|
+
} else if (!result.transaction) {
|
|
5592
|
+
result.transaction = "single";
|
|
5593
|
+
}
|
|
5594
|
+
let c = rakeDbCommands;
|
|
5595
|
+
if (config.commands) {
|
|
5596
|
+
c = { ...c };
|
|
5597
|
+
const commands = config.commands;
|
|
5598
|
+
for (const key in commands) {
|
|
5599
|
+
const command = commands[key];
|
|
5600
|
+
c[key] = typeof command === "function" ? { run: command } : command;
|
|
5601
|
+
}
|
|
5602
|
+
}
|
|
5603
|
+
result.commands = c;
|
|
5604
|
+
return result;
|
|
5605
|
+
};
|
|
5606
|
+
|
|
5607
|
+
const listMigrationsStatuses = async (adapters, config, params) => {
|
|
5608
|
+
const ctx = {};
|
|
5609
|
+
const [{ migrations }, ...migrated] = await Promise.all([
|
|
5610
|
+
getMigrations(ctx, config, true),
|
|
5611
|
+
...adapters.map((adapter) => getMigratedVersionsMap(ctx, adapter, config))
|
|
5612
|
+
]);
|
|
5613
|
+
const map = {};
|
|
5614
|
+
let maxVersionLength = 12;
|
|
5615
|
+
let maxNameLength = 4;
|
|
5616
|
+
for (let i = 0; i < adapters.length; i++) {
|
|
5617
|
+
const list = migrated[i];
|
|
5618
|
+
const key = Object.entries(list.map).map(([version, up]) => `${version}${up ? "t" : "f"}`).join("");
|
|
5619
|
+
const database = adapters[i].getDatabase();
|
|
5620
|
+
if (map[key]) {
|
|
5621
|
+
map[key].databases.push(database);
|
|
5622
|
+
continue;
|
|
5623
|
+
}
|
|
5624
|
+
map[key] = {
|
|
5625
|
+
databases: [database],
|
|
5626
|
+
migrations: migrations.map((item) => {
|
|
5627
|
+
if (item.version.length > maxVersionLength) {
|
|
5628
|
+
maxVersionLength = item.version.length;
|
|
5629
|
+
}
|
|
5630
|
+
const name = path.parse(item.path).name.slice(item.version.length + 1).replace(
|
|
5631
|
+
/([a-z])([A-Z])/g,
|
|
5632
|
+
(_, a, b) => `${a} ${b.toLocaleLowerCase()}`
|
|
5633
|
+
).replace(/[-_](.)/g, (_, char) => ` ${char.toLocaleLowerCase()}`).replace(/^\w/, (match) => match.toLocaleUpperCase());
|
|
5634
|
+
if (name.length > maxNameLength) {
|
|
5635
|
+
maxNameLength = name.length;
|
|
5636
|
+
}
|
|
5637
|
+
return {
|
|
5638
|
+
up: !!list.map[item.version],
|
|
5639
|
+
version: item.version,
|
|
5640
|
+
name,
|
|
5641
|
+
url: node_url.pathToFileURL(item.path)
|
|
5642
|
+
};
|
|
5643
|
+
})
|
|
5644
|
+
};
|
|
5645
|
+
}
|
|
5646
|
+
const showUrl = params?.showUrl;
|
|
5647
|
+
const asIs = (s) => s;
|
|
5648
|
+
const c = typeof config.log === "object" && config.log.colors === false ? {
|
|
5649
|
+
yellow: asIs,
|
|
5650
|
+
green: asIs,
|
|
5651
|
+
red: asIs,
|
|
5652
|
+
blue: asIs
|
|
5653
|
+
} : pqb.colors;
|
|
5654
|
+
const log = Object.values(map).map(({ databases, migrations: migrations2 }) => {
|
|
5655
|
+
let log2 = ` ${c.yellow("Database:")} ${databases.join(", ")}`;
|
|
5656
|
+
if (migrations2.length === 0) {
|
|
5657
|
+
return log2 + `
|
|
5418
5658
|
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
await saveMigratedVersion(silentQueries, version, "pull", config);
|
|
5432
|
-
const unsupportedEntries = Object.entries(ctx.unsupportedTypes);
|
|
5433
|
-
const len = unsupportedEntries.length;
|
|
5434
|
-
if (len) {
|
|
5435
|
-
let count = 0;
|
|
5436
|
-
config.logger?.warn(
|
|
5437
|
-
`Found unsupported types:
|
|
5438
|
-
${unsupportedEntries.map(([type, columns]) => {
|
|
5439
|
-
count += columns.length;
|
|
5440
|
-
return `- ${type} is used for column${columns.length > 1 ? "s" : ""} ${columns.join(", ")}`;
|
|
5441
|
-
}).join("\n")}
|
|
5442
|
-
Append \`as\` method manually to ${count > 1 ? "these" : "this"} column${count > 1 ? "s" : ""} to treat ${count > 1 ? "them" : "it"} as other column type`
|
|
5659
|
+
No migrations available`;
|
|
5660
|
+
}
|
|
5661
|
+
const lineSeparator = c.yellow(
|
|
5662
|
+
makeChars(14 + maxVersionLength + maxNameLength, "-")
|
|
5663
|
+
);
|
|
5664
|
+
const columnSeparator = c.yellow("|");
|
|
5665
|
+
log2 += "\n\n " + c.yellow(
|
|
5666
|
+
`Status | Migration ID${makeChars(
|
|
5667
|
+
maxVersionLength - 12,
|
|
5668
|
+
" "
|
|
5669
|
+
)} | Name
|
|
5670
|
+
${lineSeparator}`
|
|
5443
5671
|
);
|
|
5672
|
+
for (const migration of migrations2) {
|
|
5673
|
+
log2 += `
|
|
5674
|
+
${migration.up ? ` ${c.green("Up")} ` : c.red("Down")} ${columnSeparator} ${c.blue(migration.version)}${makeChars(
|
|
5675
|
+
maxVersionLength - migration.version.length,
|
|
5676
|
+
" "
|
|
5677
|
+
)} ${columnSeparator} ${migration.name}`;
|
|
5678
|
+
if (showUrl) {
|
|
5679
|
+
log2 += `
|
|
5680
|
+
${migration.url}
|
|
5681
|
+
`;
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
return log2 += showUrl ? lineSeparator : `
|
|
5685
|
+
${lineSeparator}`;
|
|
5686
|
+
}).join("\n\n");
|
|
5687
|
+
(config.logger ?? console).log(log);
|
|
5688
|
+
await Promise.all(adapters.map((adapter) => adapter.close()));
|
|
5689
|
+
};
|
|
5690
|
+
const makeChars = (count, char) => {
|
|
5691
|
+
let chars = "";
|
|
5692
|
+
for (let i = 0; i < count; i++) {
|
|
5693
|
+
chars += char;
|
|
5444
5694
|
}
|
|
5445
|
-
|
|
5695
|
+
return chars;
|
|
5446
5696
|
};
|
|
5447
5697
|
|
|
5448
5698
|
const rebase = async (adapters, config) => {
|
|
@@ -5583,11 +5833,7 @@ const rebase = async (adapters, config) => {
|
|
|
5583
5833
|
}
|
|
5584
5834
|
};
|
|
5585
5835
|
for (const adapter of adapters) {
|
|
5586
|
-
await redo({
|
|
5587
|
-
ctx,
|
|
5588
|
-
adapter,
|
|
5589
|
-
config: redoConfig
|
|
5590
|
-
});
|
|
5836
|
+
await redo(adapter, redoConfig, { ctx, count: Infinity });
|
|
5591
5837
|
}
|
|
5592
5838
|
for (let i = renames.length - 1; i >= 0; i--) {
|
|
5593
5839
|
const [from, version] = renames[i];
|
|
@@ -5602,111 +5848,52 @@ const rebase = async (adapters, config) => {
|
|
|
5602
5848
|
}
|
|
5603
5849
|
};
|
|
5604
5850
|
|
|
5605
|
-
const listMigrationsStatuses = async (adapters, config, args) => {
|
|
5606
|
-
const ctx = {};
|
|
5607
|
-
const [{ migrations }, ...migrated] = await Promise.all([
|
|
5608
|
-
getMigrations(ctx, config, true),
|
|
5609
|
-
...adapters.map((adapter) => getMigratedVersionsMap(ctx, adapter, config))
|
|
5610
|
-
]);
|
|
5611
|
-
const map = {};
|
|
5612
|
-
let maxVersionLength = 12;
|
|
5613
|
-
let maxNameLength = 4;
|
|
5614
|
-
for (let i = 0; i < adapters.length; i++) {
|
|
5615
|
-
const list = migrated[i];
|
|
5616
|
-
const key = Object.entries(list.map).map(([version, up]) => `${version}${up ? "t" : "f"}`).join("");
|
|
5617
|
-
const database = adapters[i].getDatabase();
|
|
5618
|
-
if (map[key]) {
|
|
5619
|
-
map[key].databases.push(database);
|
|
5620
|
-
continue;
|
|
5621
|
-
}
|
|
5622
|
-
map[key] = {
|
|
5623
|
-
databases: [database],
|
|
5624
|
-
migrations: migrations.map((item) => {
|
|
5625
|
-
if (item.version.length > maxVersionLength) {
|
|
5626
|
-
maxVersionLength = item.version.length;
|
|
5627
|
-
}
|
|
5628
|
-
const name = path.parse(item.path).name.slice(item.version.length + 1).replace(
|
|
5629
|
-
/([a-z])([A-Z])/g,
|
|
5630
|
-
(_, a, b) => `${a} ${b.toLocaleLowerCase()}`
|
|
5631
|
-
).replace(/[-_](.)/g, (_, char) => ` ${char.toLocaleLowerCase()}`).replace(/^\w/, (match) => match.toLocaleUpperCase());
|
|
5632
|
-
if (name.length > maxNameLength) {
|
|
5633
|
-
maxNameLength = name.length;
|
|
5634
|
-
}
|
|
5635
|
-
return {
|
|
5636
|
-
up: !!list.map[item.version],
|
|
5637
|
-
version: item.version,
|
|
5638
|
-
name,
|
|
5639
|
-
url: node_url.pathToFileURL(item.path)
|
|
5640
|
-
};
|
|
5641
|
-
})
|
|
5642
|
-
};
|
|
5643
|
-
}
|
|
5644
|
-
const showUrl = args.includes("p") || args.includes("path");
|
|
5645
|
-
const asIs = (s) => s;
|
|
5646
|
-
const c = typeof config.log === "object" && config.log.colors === false ? {
|
|
5647
|
-
yellow: asIs,
|
|
5648
|
-
green: asIs,
|
|
5649
|
-
red: asIs,
|
|
5650
|
-
blue: asIs
|
|
5651
|
-
} : pqb.colors;
|
|
5652
|
-
const log = Object.values(map).map(({ databases, migrations: migrations2 }) => {
|
|
5653
|
-
let log2 = ` ${c.yellow("Database:")} ${databases.join(", ")}`;
|
|
5654
|
-
if (migrations2.length === 0) {
|
|
5655
|
-
return log2 + `
|
|
5656
|
-
|
|
5657
|
-
No migrations available`;
|
|
5658
|
-
}
|
|
5659
|
-
const lineSeparator = c.yellow(
|
|
5660
|
-
makeChars(14 + maxVersionLength + maxNameLength, "-")
|
|
5661
|
-
);
|
|
5662
|
-
const columnSeparator = c.yellow("|");
|
|
5663
|
-
log2 += "\n\n " + c.yellow(
|
|
5664
|
-
`Status | Migration ID${makeChars(
|
|
5665
|
-
maxVersionLength - 12,
|
|
5666
|
-
" "
|
|
5667
|
-
)} | Name
|
|
5668
|
-
${lineSeparator}`
|
|
5669
|
-
);
|
|
5670
|
-
for (const migration of migrations2) {
|
|
5671
|
-
log2 += `
|
|
5672
|
-
${migration.up ? ` ${c.green("Up")} ` : c.red("Down")} ${columnSeparator} ${c.blue(migration.version)}${makeChars(
|
|
5673
|
-
maxVersionLength - migration.version.length,
|
|
5674
|
-
" "
|
|
5675
|
-
)} ${columnSeparator} ${migration.name}`;
|
|
5676
|
-
if (showUrl) {
|
|
5677
|
-
log2 += `
|
|
5678
|
-
${migration.url}
|
|
5679
|
-
`;
|
|
5680
|
-
}
|
|
5681
|
-
}
|
|
5682
|
-
return log2 += showUrl ? lineSeparator : `
|
|
5683
|
-
${lineSeparator}`;
|
|
5684
|
-
}).join("\n\n");
|
|
5685
|
-
(config.logger ?? console).log(log);
|
|
5686
|
-
await Promise.all(adapters.map((adapter) => adapter.close()));
|
|
5687
|
-
};
|
|
5688
|
-
const makeChars = (count, char) => {
|
|
5689
|
-
let chars = "";
|
|
5690
|
-
for (let i = 0; i < count; i++) {
|
|
5691
|
-
chars += char;
|
|
5692
|
-
}
|
|
5693
|
-
return chars;
|
|
5694
|
-
};
|
|
5695
|
-
|
|
5696
5851
|
const rakeDbAliases = {
|
|
5697
5852
|
migrate: "up",
|
|
5698
5853
|
rollback: "down",
|
|
5699
5854
|
s: "status",
|
|
5700
5855
|
rec: "recurrent"
|
|
5701
5856
|
};
|
|
5702
|
-
const
|
|
5857
|
+
const rakeDbCliWithAdapter = (inputConfig, args = process.argv.slice(2)) => {
|
|
5858
|
+
let config;
|
|
5859
|
+
if ("__rakeDbConfig" in inputConfig) {
|
|
5860
|
+
config = inputConfig;
|
|
5861
|
+
} else {
|
|
5862
|
+
incrementIntermediateCaller();
|
|
5863
|
+
config = makeRakeDbConfig(inputConfig, args);
|
|
5864
|
+
}
|
|
5865
|
+
return {
|
|
5866
|
+
change: makeChange(config),
|
|
5867
|
+
async run(adapter, runArgs) {
|
|
5868
|
+
const adapters = pqb.toArray(adapter);
|
|
5869
|
+
try {
|
|
5870
|
+
await runCommand(adapters, config, runArgs || args);
|
|
5871
|
+
} catch (err) {
|
|
5872
|
+
if (err instanceof RakeDbError) {
|
|
5873
|
+
config.logger?.error(err.message);
|
|
5874
|
+
process.exit(1);
|
|
5875
|
+
}
|
|
5876
|
+
throw err;
|
|
5877
|
+
}
|
|
5878
|
+
}
|
|
5879
|
+
};
|
|
5880
|
+
};
|
|
5881
|
+
const setRakeDbCliRunFn = (rakeDbCli, mapper) => {
|
|
5882
|
+
rakeDbCli.run = (adapter, inputConfig, args) => {
|
|
5883
|
+
const { change, run } = rakeDbCli(inputConfig, args);
|
|
5884
|
+
run(mapper(adapter));
|
|
5885
|
+
return change;
|
|
5886
|
+
};
|
|
5887
|
+
};
|
|
5888
|
+
setRakeDbCliRunFn(rakeDbCliWithAdapter, (x) => x);
|
|
5889
|
+
const runCommand = async (adapters, config, args) => {
|
|
5703
5890
|
let arg = args[0]?.split(":")[0];
|
|
5704
5891
|
if (rakeDbAliases[arg]) {
|
|
5705
5892
|
args = [...args];
|
|
5706
5893
|
arg = args[0] = rakeDbAliases[arg];
|
|
5707
5894
|
}
|
|
5708
5895
|
args.shift();
|
|
5709
|
-
const command =
|
|
5896
|
+
const command = config.commands[arg]?.run;
|
|
5710
5897
|
if (command) {
|
|
5711
5898
|
await command(adapters, config, args);
|
|
5712
5899
|
} else if (config.logger) {
|
|
@@ -5714,8 +5901,8 @@ const runCommand = async (adapters, config, args = process.argv.slice(2)) => {
|
|
|
5714
5901
|
let max = 0;
|
|
5715
5902
|
let maxArgs = 0;
|
|
5716
5903
|
const addedCommands = /* @__PURE__ */ new Map();
|
|
5717
|
-
for (let key in
|
|
5718
|
-
const command2 =
|
|
5904
|
+
for (let key in config.commands) {
|
|
5905
|
+
const command2 = config.commands[key];
|
|
5719
5906
|
const added = addedCommands.get(command2);
|
|
5720
5907
|
if (added) key = added[0] += `, ${key}`;
|
|
5721
5908
|
if (key.length > max) max = key.length;
|
|
@@ -5726,7 +5913,11 @@ const runCommand = async (adapters, config, args = process.argv.slice(2)) => {
|
|
|
5726
5913
|
...Object.keys(command2.helpArguments).map((key2) => key2.length + 5)
|
|
5727
5914
|
);
|
|
5728
5915
|
}
|
|
5729
|
-
const helpBlock = [
|
|
5916
|
+
const helpBlock = [
|
|
5917
|
+
key,
|
|
5918
|
+
command2.help || "undocumented custom command",
|
|
5919
|
+
command2.helpArguments
|
|
5920
|
+
];
|
|
5730
5921
|
addedCommands.set(command2, helpBlock);
|
|
5731
5922
|
if (command2.helpAfter) {
|
|
5732
5923
|
const i = commandsHelp.findIndex(([key2]) => key2 === command2.helpAfter);
|
|
@@ -5762,15 +5953,16 @@ ${Object.entries(helpArguments).map(
|
|
|
5762
5953
|
}).join("\n\n")}
|
|
5763
5954
|
`);
|
|
5764
5955
|
}
|
|
5765
|
-
return {
|
|
5766
|
-
adapters,
|
|
5767
|
-
config,
|
|
5768
|
-
args
|
|
5769
|
-
};
|
|
5770
5956
|
};
|
|
5771
5957
|
const close = (adapters) => Promise.all(adapters.map((adapter) => adapter.close()));
|
|
5958
|
+
const maybeRunRecurrent = async (adapters, config) => {
|
|
5959
|
+
config.recurrentPath && await runRecurrentMigrations(
|
|
5960
|
+
adapters,
|
|
5961
|
+
config
|
|
5962
|
+
);
|
|
5963
|
+
};
|
|
5772
5964
|
const upCommand = {
|
|
5773
|
-
run: (adapters, config, args) => migrateCommand(adapters, config, args).then(() =>
|
|
5965
|
+
run: (adapters, config, args) => migrateCommand(adapters, config, args).then(() => maybeRunRecurrent(adapters, config)).then(() => close(adapters)),
|
|
5774
5966
|
help: "migrate pending migrations",
|
|
5775
5967
|
helpArguments: {
|
|
5776
5968
|
"no arguments": "migrate all pending",
|
|
@@ -5788,36 +5980,40 @@ const downCommand = {
|
|
|
5788
5980
|
}
|
|
5789
5981
|
};
|
|
5790
5982
|
const statusCommand = {
|
|
5791
|
-
run
|
|
5983
|
+
run(adapters, config, args) {
|
|
5984
|
+
const showUrl = args.includes("p") || args.includes("path");
|
|
5985
|
+
return listMigrationsStatuses(adapters, config, { showUrl });
|
|
5986
|
+
},
|
|
5792
5987
|
help: "list migrations statuses",
|
|
5793
5988
|
helpArguments: {
|
|
5794
5989
|
"no arguments": `does not print file paths`,
|
|
5795
5990
|
"p, path": "also print file paths"
|
|
5796
5991
|
}
|
|
5797
5992
|
};
|
|
5798
|
-
const
|
|
5799
|
-
run
|
|
5993
|
+
const recurrent = {
|
|
5994
|
+
async run(adapters, config) {
|
|
5995
|
+
if (!config.recurrentPath) return;
|
|
5996
|
+
await maybeRunRecurrent(adapters, config).then(() => close(adapters));
|
|
5997
|
+
},
|
|
5800
5998
|
help: "run recurrent migrations"
|
|
5801
5999
|
};
|
|
5802
6000
|
const rakeDbCommands = {
|
|
5803
6001
|
create: {
|
|
5804
|
-
run:
|
|
6002
|
+
run: (adapters, config) => createDatabaseCommand(adapters, config),
|
|
5805
6003
|
help: "create databases"
|
|
5806
6004
|
},
|
|
5807
6005
|
drop: {
|
|
5808
|
-
run:
|
|
6006
|
+
run: dropDatabaseCommand,
|
|
5809
6007
|
help: "drop databases"
|
|
5810
6008
|
},
|
|
5811
6009
|
reset: {
|
|
5812
|
-
run: (adapters, config) =>
|
|
6010
|
+
run: (adapters, config) => resetDatabaseCommand(adapters, config),
|
|
5813
6011
|
help: "drop, create and migrate databases"
|
|
5814
6012
|
},
|
|
5815
6013
|
up: upCommand,
|
|
5816
|
-
migrate: upCommand,
|
|
5817
6014
|
down: downCommand,
|
|
5818
|
-
rollback: downCommand,
|
|
5819
6015
|
redo: {
|
|
5820
|
-
run: (adapters, config, args) => redoCommand(adapters, config, args).then(() =>
|
|
6016
|
+
run: (adapters, config, args) => redoCommand(adapters, config, args).then(() => maybeRunRecurrent(adapters, config)).then(() => close(adapters)),
|
|
5821
6017
|
help: "rollback and migrate, run recurrent"
|
|
5822
6018
|
},
|
|
5823
6019
|
pull: {
|
|
@@ -5825,19 +6021,32 @@ const rakeDbCommands = {
|
|
|
5825
6021
|
help: "generate a combined migration for an existing database"
|
|
5826
6022
|
},
|
|
5827
6023
|
new: {
|
|
5828
|
-
run
|
|
6024
|
+
run(_, config, args) {
|
|
6025
|
+
const [name] = args;
|
|
6026
|
+
if (!name) throw new Error("Migration name is missing");
|
|
6027
|
+
return newMigration(config, name);
|
|
6028
|
+
},
|
|
5829
6029
|
help: "create new migration file"
|
|
5830
6030
|
},
|
|
5831
|
-
s: statusCommand,
|
|
5832
6031
|
status: statusCommand,
|
|
5833
|
-
|
|
5834
|
-
recurrent: recurrentCommand,
|
|
6032
|
+
recurrent,
|
|
5835
6033
|
rebase: {
|
|
5836
6034
|
run: (adapters, config) => rebase(adapters, config).then(() => close(adapters)),
|
|
5837
6035
|
help: "move local migrations below the new ones from upstream"
|
|
5838
6036
|
},
|
|
5839
6037
|
"change-ids": {
|
|
5840
|
-
run
|
|
6038
|
+
run(adapters, config, [format, digitsArg]) {
|
|
6039
|
+
if (format !== "serial" && format !== "timestamp") {
|
|
6040
|
+
throw new Error(
|
|
6041
|
+
`Pass "serial" or "timestamp" argument to the "change-ids" command`
|
|
6042
|
+
);
|
|
6043
|
+
}
|
|
6044
|
+
const digits = digitsArg ? parseInt(digitsArg) : void 0;
|
|
6045
|
+
if (digits && isNaN(digits)) {
|
|
6046
|
+
throw new Error(`Second argument is optional and must be an integer`);
|
|
6047
|
+
}
|
|
6048
|
+
return changeIds(adapters, config, { format, digits });
|
|
6049
|
+
},
|
|
5841
6050
|
help: "change migrations ids format",
|
|
5842
6051
|
helpArguments: {
|
|
5843
6052
|
serial: "change ids to 4 digit serial",
|
|
@@ -5846,68 +6055,10 @@ const rakeDbCommands = {
|
|
|
5846
6055
|
}
|
|
5847
6056
|
}
|
|
5848
6057
|
};
|
|
5849
|
-
|
|
5850
|
-
const
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
adapters,
|
|
5854
|
-
config,
|
|
5855
|
-
args
|
|
5856
|
-
).catch((err) => {
|
|
5857
|
-
if (err instanceof RakeDbError) {
|
|
5858
|
-
config.logger?.error(err.message);
|
|
5859
|
-
process.exit(1);
|
|
5860
|
-
}
|
|
5861
|
-
throw err;
|
|
5862
|
-
});
|
|
5863
|
-
return Object.assign(makeChange(config), {
|
|
5864
|
-
promise
|
|
5865
|
-
});
|
|
5866
|
-
};
|
|
5867
|
-
rakeDbWithAdapters.lazy = (adapters, partialConfig) => {
|
|
5868
|
-
const config = processRakeDbConfig(partialConfig);
|
|
5869
|
-
return {
|
|
5870
|
-
change: makeChange(config),
|
|
5871
|
-
run(args, conf) {
|
|
5872
|
-
return runCommand(adapters, conf ? { ...config, ...conf } : config, args);
|
|
5873
|
-
}
|
|
5874
|
-
};
|
|
5875
|
-
};
|
|
5876
|
-
const makeChange = (config) => (fn) => {
|
|
5877
|
-
const change = { fn, config };
|
|
5878
|
-
pushChange(change);
|
|
5879
|
-
return change;
|
|
5880
|
-
};
|
|
5881
|
-
|
|
5882
|
-
const migrateFiles = async (db, files) => {
|
|
5883
|
-
const qb = db.$qb;
|
|
5884
|
-
await qb.ensureTransaction(async () => {
|
|
5885
|
-
const adapter = qb.internal.transactionStorage.getStore()?.adapter;
|
|
5886
|
-
for (const load of files) {
|
|
5887
|
-
clearChanges();
|
|
5888
|
-
const changes = await getChanges({ load });
|
|
5889
|
-
const config = changes[0]?.config;
|
|
5890
|
-
await runMigration(adapter, true, changes, config);
|
|
5891
|
-
}
|
|
5892
|
-
});
|
|
5893
|
-
};
|
|
5894
|
-
const makeMigrateAdapter = (config) => {
|
|
5895
|
-
const conf = ensureMigrationsPath(ensureBasePathAndDbScript(config || {}));
|
|
5896
|
-
return async (adapter, params) => {
|
|
5897
|
-
await migrateAndClose({
|
|
5898
|
-
adapter,
|
|
5899
|
-
...params,
|
|
5900
|
-
config: {
|
|
5901
|
-
...conf,
|
|
5902
|
-
columnTypes: conf.columnTypes || pqb.makeColumnTypes(pqb.defaultSchemaConfig),
|
|
5903
|
-
migrationId: conf.migrationId || migrationConfigDefaults.migrationId,
|
|
5904
|
-
migrationsTable: conf.migrationsTable || migrationConfigDefaults.migrationsTable,
|
|
5905
|
-
import: conf.import || migrationConfigDefaults.import,
|
|
5906
|
-
transaction: conf.transaction || "single"
|
|
5907
|
-
}
|
|
5908
|
-
});
|
|
5909
|
-
};
|
|
5910
|
-
};
|
|
6058
|
+
for (const key in rakeDbAliases) {
|
|
6059
|
+
const command = rakeDbAliases[key];
|
|
6060
|
+
if (command) rakeDbCommands[key] = rakeDbCommands[command];
|
|
6061
|
+
}
|
|
5911
6062
|
|
|
5912
6063
|
exports.RakeDbError = RakeDbError;
|
|
5913
6064
|
exports.astToMigration = astToMigration;
|
|
@@ -5922,23 +6073,24 @@ exports.getExcludeName = getExcludeName;
|
|
|
5922
6073
|
exports.getIndexName = getIndexName;
|
|
5923
6074
|
exports.getMigrationsSchemaAndTable = getMigrationsSchemaAndTable;
|
|
5924
6075
|
exports.getSchemaAndTableFromName = getSchemaAndTableFromName;
|
|
6076
|
+
exports.incrementIntermediateCaller = incrementIntermediateCaller;
|
|
5925
6077
|
exports.instantiateDbColumn = instantiateDbColumn;
|
|
5926
6078
|
exports.introspectDbSchema = introspectDbSchema;
|
|
5927
|
-
exports.makeChange = makeChange;
|
|
5928
6079
|
exports.makeDomainsMap = makeDomainsMap;
|
|
5929
6080
|
exports.makeFileVersion = makeFileVersion;
|
|
5930
|
-
exports.
|
|
6081
|
+
exports.makeRakeDbConfig = makeRakeDbConfig;
|
|
5931
6082
|
exports.makeStructureToAstCtx = makeStructureToAstCtx;
|
|
5932
6083
|
exports.migrate = migrate;
|
|
5933
6084
|
exports.migrateAndClose = migrateAndClose;
|
|
5934
|
-
exports.migrateFiles = migrateFiles;
|
|
5935
6085
|
exports.migrationConfigDefaults = migrationConfigDefaults;
|
|
5936
|
-
exports.processRakeDbConfig = processRakeDbConfig;
|
|
5937
6086
|
exports.promptSelect = promptSelect;
|
|
6087
|
+
exports.rakeDbCliWithAdapter = rakeDbCliWithAdapter;
|
|
5938
6088
|
exports.rakeDbCommands = rakeDbCommands;
|
|
5939
|
-
exports.
|
|
5940
|
-
exports.
|
|
6089
|
+
exports.redo = redo;
|
|
6090
|
+
exports.rollback = rollback;
|
|
6091
|
+
exports.runMigration = runMigration;
|
|
5941
6092
|
exports.saveMigratedVersion = saveMigratedVersion;
|
|
6093
|
+
exports.setRakeDbCliRunFn = setRakeDbCliRunFn;
|
|
5942
6094
|
exports.structureToAst = structureToAst;
|
|
5943
6095
|
exports.tableToAst = tableToAst;
|
|
5944
6096
|
exports.writeMigrationFile = writeMigrationFile;
|