rake-db 2.0.7 → 2.0.9
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/.env.local +1 -0
- package/db.ts +6 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.esm.js +169 -151
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +168 -149
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/createOrDrop.test.ts +25 -1
- package/src/commands/createOrDrop.ts +7 -0
- package/src/commands/migrateOrRollback.ts +14 -4
- package/src/migration/change.ts +7 -1
- package/src/rakeDb.ts +7 -4
package/dist/index.js
CHANGED
|
@@ -190,156 +190,15 @@ const quoteTable = (table) => {
|
|
|
190
190
|
}
|
|
191
191
|
};
|
|
192
192
|
|
|
193
|
-
const execute = async (options, sql) => {
|
|
194
|
-
const db = new pqb.Adapter(options);
|
|
195
|
-
try {
|
|
196
|
-
await db.query(sql);
|
|
197
|
-
return "ok";
|
|
198
|
-
} catch (error) {
|
|
199
|
-
const err = error;
|
|
200
|
-
if (err.code === "42P04" || err.code === "3D000") {
|
|
201
|
-
return "already";
|
|
202
|
-
} else if (err.code === "42501") {
|
|
203
|
-
return "forbidden";
|
|
204
|
-
} else {
|
|
205
|
-
return { error };
|
|
206
|
-
}
|
|
207
|
-
} finally {
|
|
208
|
-
await db.destroy();
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
const createOrDrop = async (options, adminOptions, config, args) => {
|
|
212
|
-
const params = getDatabaseAndUserFromOptions(options);
|
|
213
|
-
const result = await execute(
|
|
214
|
-
setAdapterOptions(adminOptions, { database: "postgres" }),
|
|
215
|
-
args.sql(params)
|
|
216
|
-
);
|
|
217
|
-
if (result === "ok") {
|
|
218
|
-
console.log(args.successMessage(params));
|
|
219
|
-
} else if (result === "already") {
|
|
220
|
-
console.log(args.alreadyMessage(params));
|
|
221
|
-
} else if (result === "forbidden") {
|
|
222
|
-
await createOrDrop(
|
|
223
|
-
options,
|
|
224
|
-
await setAdminCredentialsToOptions(options),
|
|
225
|
-
config,
|
|
226
|
-
args
|
|
227
|
-
);
|
|
228
|
-
return;
|
|
229
|
-
} else {
|
|
230
|
-
throw result.error;
|
|
231
|
-
}
|
|
232
|
-
if (!args.createVersionsTable)
|
|
233
|
-
return;
|
|
234
|
-
const db = new pqb.Adapter(options);
|
|
235
|
-
await createSchemaMigrations(db, config);
|
|
236
|
-
await db.destroy();
|
|
237
|
-
};
|
|
238
|
-
const createDb = async (arg, config) => {
|
|
239
|
-
for (const options of pqb.toArray(arg)) {
|
|
240
|
-
await createOrDrop(options, options, config, {
|
|
241
|
-
sql({ database, user }) {
|
|
242
|
-
return `CREATE DATABASE "${database}" OWNER "${user}"`;
|
|
243
|
-
},
|
|
244
|
-
successMessage({ database }) {
|
|
245
|
-
return `Database ${database} successfully created`;
|
|
246
|
-
},
|
|
247
|
-
alreadyMessage({ database }) {
|
|
248
|
-
return `Database ${database} already exists`;
|
|
249
|
-
},
|
|
250
|
-
createVersionsTable: true
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
const dropDb = async (arg) => {
|
|
255
|
-
for (const options of pqb.toArray(arg)) {
|
|
256
|
-
await createOrDrop(options, options, migrationConfigDefaults, {
|
|
257
|
-
sql({ database }) {
|
|
258
|
-
return `DROP DATABASE "${database}"`;
|
|
259
|
-
},
|
|
260
|
-
successMessage({ database }) {
|
|
261
|
-
return `Database ${database} was successfully dropped`;
|
|
262
|
-
},
|
|
263
|
-
alreadyMessage({ database }) {
|
|
264
|
-
return `Database ${database} does not exist`;
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const generate = async (config, args) => {
|
|
271
|
-
const name = args[0];
|
|
272
|
-
if (!name)
|
|
273
|
-
throw new Error("Migration name is missing");
|
|
274
|
-
await promises.mkdir(config.migrationsPath, { recursive: true });
|
|
275
|
-
const filePath = path__default["default"].resolve(
|
|
276
|
-
config.migrationsPath,
|
|
277
|
-
`${makeFileTimeStamp()}_${name}.ts`
|
|
278
|
-
);
|
|
279
|
-
await promises.writeFile(filePath, makeContent(name, args.slice(1)));
|
|
280
|
-
console.log(`Created ${filePath}`);
|
|
281
|
-
};
|
|
282
|
-
const makeFileTimeStamp = () => {
|
|
283
|
-
const now = new Date();
|
|
284
|
-
return [
|
|
285
|
-
now.getUTCFullYear(),
|
|
286
|
-
now.getUTCMonth() + 1,
|
|
287
|
-
now.getUTCDate(),
|
|
288
|
-
now.getUTCHours(),
|
|
289
|
-
now.getUTCMinutes(),
|
|
290
|
-
now.getUTCSeconds()
|
|
291
|
-
].map((value) => value < 10 ? `0${value}` : value).join("");
|
|
292
|
-
};
|
|
293
|
-
const makeContent = (name, args) => {
|
|
294
|
-
let content = `import { change } from 'rake-db';
|
|
295
|
-
|
|
296
|
-
change(async (db) => {`;
|
|
297
|
-
const [first, rest] = getFirstWordAndRest(name);
|
|
298
|
-
if (rest) {
|
|
299
|
-
if (first === "create" || first === "drop") {
|
|
300
|
-
content += `
|
|
301
|
-
await db.${first === "create" ? "createTable" : "dropTable"}('${rest}', (t) => ({`;
|
|
302
|
-
content += makeColumnsContent(args);
|
|
303
|
-
content += "\n }));";
|
|
304
|
-
} else if (first === "change") {
|
|
305
|
-
content += `
|
|
306
|
-
await db.changeTable('${rest}', (t) => ({`;
|
|
307
|
-
content += "\n }));";
|
|
308
|
-
} else if (first === "add" || first === "remove") {
|
|
309
|
-
const table = first === "add" ? getTextAfterTo(rest) : getTextAfterFrom(rest);
|
|
310
|
-
content += `
|
|
311
|
-
await db.changeTable(${table ? `'${table}'` : "tableName"}, (t) => ({`;
|
|
312
|
-
content += makeColumnsContent(args, first);
|
|
313
|
-
content += "\n }));";
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return content + "\n});\n";
|
|
317
|
-
};
|
|
318
|
-
const makeColumnsContent = (args, method) => {
|
|
319
|
-
let content = "";
|
|
320
|
-
const prepend = method ? `t.${method}(` : "";
|
|
321
|
-
const append = method ? ")" : "";
|
|
322
|
-
for (const arg of args) {
|
|
323
|
-
const [name, def] = arg.split(":");
|
|
324
|
-
if (!def) {
|
|
325
|
-
throw new Error(
|
|
326
|
-
`Column argument should be similar to name:type, name:type.method1.method2, name:type(arg).method(arg). Example: name:varchar(20).nullable. Received: ${arg}`
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
|
-
const methods = def.split(".").map((method2) => method2.endsWith(")") ? `.${method2}` : `.${method2}()`);
|
|
330
|
-
content += `
|
|
331
|
-
${name}: ${prepend}t${methods.join("")}${append},`;
|
|
332
|
-
}
|
|
333
|
-
return content;
|
|
334
|
-
};
|
|
335
|
-
|
|
336
193
|
let currentMigration;
|
|
337
194
|
let currentPromise;
|
|
338
195
|
let currentUp = true;
|
|
196
|
+
let currentChangeCallback;
|
|
339
197
|
const change = (fn) => {
|
|
340
198
|
if (!currentMigration)
|
|
341
199
|
throw new Error("Database instance is not set");
|
|
342
200
|
currentPromise = fn(currentMigration, currentUp);
|
|
201
|
+
currentChangeCallback = fn;
|
|
343
202
|
};
|
|
344
203
|
const setCurrentMigration = (db) => {
|
|
345
204
|
currentMigration = db;
|
|
@@ -348,6 +207,7 @@ const setCurrentMigrationUp = (up) => {
|
|
|
348
207
|
currentUp = up;
|
|
349
208
|
};
|
|
350
209
|
const getCurrentPromise = () => currentPromise;
|
|
210
|
+
const getCurrentChangeCallback = () => currentChangeCallback;
|
|
351
211
|
|
|
352
212
|
var __defProp$2 = Object.defineProperty;
|
|
353
213
|
var __defProps$2 = Object.defineProperties;
|
|
@@ -1099,12 +959,19 @@ const migrateOrRollback = async (options, config, args, up) => {
|
|
|
1099
959
|
}
|
|
1100
960
|
}
|
|
1101
961
|
};
|
|
962
|
+
const changeCache = {};
|
|
1102
963
|
const processMigration = async (db, up, file, config) => {
|
|
1103
964
|
await db.transaction(async (tx) => {
|
|
1104
965
|
const db2 = new Migration(tx, up, config);
|
|
1105
966
|
setCurrentMigration(db2);
|
|
1106
967
|
setCurrentMigrationUp(up);
|
|
1107
|
-
|
|
968
|
+
const callback = changeCache[file.path];
|
|
969
|
+
if (callback) {
|
|
970
|
+
change(callback);
|
|
971
|
+
} else {
|
|
972
|
+
config.requireTs(file.path);
|
|
973
|
+
changeCache[file.path] = getCurrentChangeCallback();
|
|
974
|
+
}
|
|
1108
975
|
await getCurrentPromise();
|
|
1109
976
|
await (up ? saveMigratedVersion : removeMigratedVersion)(
|
|
1110
977
|
db2,
|
|
@@ -1139,8 +1006,156 @@ const getMigratedVersionsMap = async (db, config) => {
|
|
|
1139
1006
|
throw err;
|
|
1140
1007
|
}
|
|
1141
1008
|
};
|
|
1142
|
-
const migrate = (options, config, args) => migrateOrRollback(options, config, args, true);
|
|
1143
|
-
const rollback = (options, config, args) => migrateOrRollback(options, config, args, false);
|
|
1009
|
+
const migrate = (options, config, args = []) => migrateOrRollback(options, config, args, true);
|
|
1010
|
+
const rollback = (options, config, args = []) => migrateOrRollback(options, config, args, false);
|
|
1011
|
+
|
|
1012
|
+
const execute = async (options, sql) => {
|
|
1013
|
+
const db = new pqb.Adapter(options);
|
|
1014
|
+
try {
|
|
1015
|
+
await db.query(sql);
|
|
1016
|
+
return "ok";
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
const err = error;
|
|
1019
|
+
if (err.code === "42P04" || err.code === "3D000") {
|
|
1020
|
+
return "already";
|
|
1021
|
+
} else if (err.code === "42501") {
|
|
1022
|
+
return "forbidden";
|
|
1023
|
+
} else {
|
|
1024
|
+
return { error };
|
|
1025
|
+
}
|
|
1026
|
+
} finally {
|
|
1027
|
+
await db.destroy();
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
const createOrDrop = async (options, adminOptions, config, args) => {
|
|
1031
|
+
const params = getDatabaseAndUserFromOptions(options);
|
|
1032
|
+
const result = await execute(
|
|
1033
|
+
setAdapterOptions(adminOptions, { database: "postgres" }),
|
|
1034
|
+
args.sql(params)
|
|
1035
|
+
);
|
|
1036
|
+
if (result === "ok") {
|
|
1037
|
+
console.log(args.successMessage(params));
|
|
1038
|
+
} else if (result === "already") {
|
|
1039
|
+
console.log(args.alreadyMessage(params));
|
|
1040
|
+
} else if (result === "forbidden") {
|
|
1041
|
+
await createOrDrop(
|
|
1042
|
+
options,
|
|
1043
|
+
await setAdminCredentialsToOptions(options),
|
|
1044
|
+
config,
|
|
1045
|
+
args
|
|
1046
|
+
);
|
|
1047
|
+
return;
|
|
1048
|
+
} else {
|
|
1049
|
+
throw result.error;
|
|
1050
|
+
}
|
|
1051
|
+
if (!args.createVersionsTable)
|
|
1052
|
+
return;
|
|
1053
|
+
const db = new pqb.Adapter(options);
|
|
1054
|
+
await createSchemaMigrations(db, config);
|
|
1055
|
+
await db.destroy();
|
|
1056
|
+
};
|
|
1057
|
+
const createDb = async (arg, config) => {
|
|
1058
|
+
for (const options of pqb.toArray(arg)) {
|
|
1059
|
+
await createOrDrop(options, options, config, {
|
|
1060
|
+
sql({ database, user }) {
|
|
1061
|
+
return `CREATE DATABASE "${database}" OWNER "${user}"`;
|
|
1062
|
+
},
|
|
1063
|
+
successMessage({ database }) {
|
|
1064
|
+
return `Database ${database} successfully created`;
|
|
1065
|
+
},
|
|
1066
|
+
alreadyMessage({ database }) {
|
|
1067
|
+
return `Database ${database} already exists`;
|
|
1068
|
+
},
|
|
1069
|
+
createVersionsTable: true
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
const dropDb = async (arg) => {
|
|
1074
|
+
for (const options of pqb.toArray(arg)) {
|
|
1075
|
+
await createOrDrop(options, options, migrationConfigDefaults, {
|
|
1076
|
+
sql({ database }) {
|
|
1077
|
+
return `DROP DATABASE "${database}"`;
|
|
1078
|
+
},
|
|
1079
|
+
successMessage({ database }) {
|
|
1080
|
+
return `Database ${database} was successfully dropped`;
|
|
1081
|
+
},
|
|
1082
|
+
alreadyMessage({ database }) {
|
|
1083
|
+
return `Database ${database} does not exist`;
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
const resetDb = async (arg, config) => {
|
|
1089
|
+
await dropDb(arg);
|
|
1090
|
+
await createDb(arg, config);
|
|
1091
|
+
await migrate(arg, config);
|
|
1092
|
+
};
|
|
1093
|
+
|
|
1094
|
+
const generate = async (config, args) => {
|
|
1095
|
+
const name = args[0];
|
|
1096
|
+
if (!name)
|
|
1097
|
+
throw new Error("Migration name is missing");
|
|
1098
|
+
await promises.mkdir(config.migrationsPath, { recursive: true });
|
|
1099
|
+
const filePath = path__default["default"].resolve(
|
|
1100
|
+
config.migrationsPath,
|
|
1101
|
+
`${makeFileTimeStamp()}_${name}.ts`
|
|
1102
|
+
);
|
|
1103
|
+
await promises.writeFile(filePath, makeContent(name, args.slice(1)));
|
|
1104
|
+
console.log(`Created ${filePath}`);
|
|
1105
|
+
};
|
|
1106
|
+
const makeFileTimeStamp = () => {
|
|
1107
|
+
const now = new Date();
|
|
1108
|
+
return [
|
|
1109
|
+
now.getUTCFullYear(),
|
|
1110
|
+
now.getUTCMonth() + 1,
|
|
1111
|
+
now.getUTCDate(),
|
|
1112
|
+
now.getUTCHours(),
|
|
1113
|
+
now.getUTCMinutes(),
|
|
1114
|
+
now.getUTCSeconds()
|
|
1115
|
+
].map((value) => value < 10 ? `0${value}` : value).join("");
|
|
1116
|
+
};
|
|
1117
|
+
const makeContent = (name, args) => {
|
|
1118
|
+
let content = `import { change } from 'rake-db';
|
|
1119
|
+
|
|
1120
|
+
change(async (db) => {`;
|
|
1121
|
+
const [first, rest] = getFirstWordAndRest(name);
|
|
1122
|
+
if (rest) {
|
|
1123
|
+
if (first === "create" || first === "drop") {
|
|
1124
|
+
content += `
|
|
1125
|
+
await db.${first === "create" ? "createTable" : "dropTable"}('${rest}', (t) => ({`;
|
|
1126
|
+
content += makeColumnsContent(args);
|
|
1127
|
+
content += "\n }));";
|
|
1128
|
+
} else if (first === "change") {
|
|
1129
|
+
content += `
|
|
1130
|
+
await db.changeTable('${rest}', (t) => ({`;
|
|
1131
|
+
content += "\n }));";
|
|
1132
|
+
} else if (first === "add" || first === "remove") {
|
|
1133
|
+
const table = first === "add" ? getTextAfterTo(rest) : getTextAfterFrom(rest);
|
|
1134
|
+
content += `
|
|
1135
|
+
await db.changeTable(${table ? `'${table}'` : "tableName"}, (t) => ({`;
|
|
1136
|
+
content += makeColumnsContent(args, first);
|
|
1137
|
+
content += "\n }));";
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return content + "\n});\n";
|
|
1141
|
+
};
|
|
1142
|
+
const makeColumnsContent = (args, method) => {
|
|
1143
|
+
let content = "";
|
|
1144
|
+
const prepend = method ? `t.${method}(` : "";
|
|
1145
|
+
const append = method ? ")" : "";
|
|
1146
|
+
for (const arg of args) {
|
|
1147
|
+
const [name, def] = arg.split(":");
|
|
1148
|
+
if (!def) {
|
|
1149
|
+
throw new Error(
|
|
1150
|
+
`Column argument should be similar to name:type, name:type.method1.method2, name:type(arg).method(arg). Example: name:varchar(20).nullable. Received: ${arg}`
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
const methods = def.split(".").map((method2) => method2.endsWith(")") ? `.${method2}` : `.${method2}()`);
|
|
1154
|
+
content += `
|
|
1155
|
+
${name}: ${prepend}t${methods.join("")}${append},`;
|
|
1156
|
+
}
|
|
1157
|
+
return content;
|
|
1158
|
+
};
|
|
1144
1159
|
|
|
1145
1160
|
const rakeDb = async (options, partialConfig = {}, args = process.argv.slice(2)) => {
|
|
1146
1161
|
const config = getMigrationConfigWithDefaults(partialConfig);
|
|
@@ -1149,6 +1164,8 @@ const rakeDb = async (options, partialConfig = {}, args = process.argv.slice(2))
|
|
|
1149
1164
|
await createDb(options, config);
|
|
1150
1165
|
} else if (command === "drop") {
|
|
1151
1166
|
await dropDb(options);
|
|
1167
|
+
} else if (command === "reset") {
|
|
1168
|
+
await resetDb(options, config);
|
|
1152
1169
|
} else if (command === "migrate") {
|
|
1153
1170
|
await migrate(options, config, args.slice(1));
|
|
1154
1171
|
} else if (command === "rollback") {
|
|
@@ -1163,9 +1180,10 @@ const printHelp = () => console.log(
|
|
|
1163
1180
|
`Usage: rake-db [command] [arguments]
|
|
1164
1181
|
|
|
1165
1182
|
Commands:
|
|
1166
|
-
create
|
|
1167
|
-
drop
|
|
1168
|
-
|
|
1183
|
+
create create databases
|
|
1184
|
+
drop drop databases
|
|
1185
|
+
reset drop, create and migrate databases
|
|
1186
|
+
g, generate generate migration file, see below
|
|
1169
1187
|
migrate migrate all pending migrations
|
|
1170
1188
|
rollback rollback the last migrated
|
|
1171
1189
|
no or unknown command prints this message
|
|
@@ -1190,5 +1208,6 @@ exports.dropDb = dropDb;
|
|
|
1190
1208
|
exports.generate = generate;
|
|
1191
1209
|
exports.migrate = migrate;
|
|
1192
1210
|
exports.rakeDb = rakeDb;
|
|
1211
|
+
exports.resetDb = resetDb;
|
|
1193
1212
|
exports.rollback = rollback;
|
|
1194
1213
|
//# sourceMappingURL=index.js.map
|