Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend config for tuning migrations DB records #394

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ module.exports = {
// The mongodb collection where the applied changes are stored. Only edit this when really necessary.
changelogCollectionName: "changelog",

// Field in collection to store migration name
nameField: 'fileName',

// Prefix for migration name
namePrefix: '',

// Whether name should include file extension
nameWithoutExtension: false,

// Field in collection to store migration applied date
dateField: 'appliedAt',

// The file extension to create migrations and search for in migration dir
migrationFileExtension: ".js",

Expand Down
16 changes: 10 additions & 6 deletions lib/actions/down.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ const hasCallback = require('../utils/has-callback');
module.exports = async (db, client) => {
const downgraded = [];
const statusItems = await status(db);
const appliedItems = statusItems.filter(item => item.appliedAt !== "PENDING");
const {
changelogCollectionName,
dateField,
nameField,
} = await config.read();
const appliedItems = statusItems.filter(item => item[dateField] !== "PENDING");
const lastAppliedItem = _.last(appliedItems);

if (lastAppliedItem) {
try {
const migration = await migrationsDir.loadMigration(lastAppliedItem.fileName);
const migration = await migrationsDir.loadMigration(lastAppliedItem.file);
const down = hasCallback(migration.down) ? promisify(migration.down) : migration.down;

if (hasCallback(migration.down) && fnArgs(migration.down).length < 3) {
Expand All @@ -27,14 +32,13 @@ module.exports = async (db, client) => {

} catch (err) {
throw new Error(
`Could not migrate down ${lastAppliedItem.fileName}: ${err.message}`
`Could not migrate down ${lastAppliedItem.file}: ${err.message}`
);
}
const { changelogCollectionName } = await config.read();
const changelogCollection = db.collection(changelogCollectionName);
try {
await changelogCollection.deleteOne({ fileName: lastAppliedItem.fileName });
downgraded.push(lastAppliedItem.fileName);
await changelogCollection.deleteOne({ [nameField]: lastAppliedItem[nameField] });
downgraded.push(lastAppliedItem.file);
} catch (err) {
throw new Error(`Could not update changelog: ${err.message}`);
}
Expand Down
33 changes: 23 additions & 10 deletions lib/actions/status.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
const { find } = require("lodash");
const migrationsDir = require("../env/migrationsDir");
const config = require("../env/config");
const getName = require('../utils/name');

module.exports = async db => {
await migrationsDir.shouldExist();
await config.shouldExist();
const fileNames = await migrationsDir.getFileNames();
const configObject = await config.read()
const {
changelogCollectionName,
useFileHash,
nameField,
dateField,
} = configObject;

const { changelogCollectionName, useFileHash } = await config.read();
const changelogCollection = db.collection(changelogCollectionName);
const changelog = await changelogCollection.find({}).toArray();

const fileNames = await migrationsDir.getFileNames();
const changelog = await changelogCollection.find({}).toArray();

const useFileHashTest = useFileHash === true;
const statusTable = await Promise.all(fileNames.map(async (fileName) => {
return Promise.all(fileNames.map(async (fileName) => {
const migrationName = getName(configObject, fileName);

let fileHash;
let findTest = { fileName };
let findTest = { [nameField]: migrationName };
if (useFileHashTest) {
fileHash = await migrationsDir.loadFileHash(fileName);
findTest = { fileName, fileHash };
findTest = { [nameField]: migrationName, fileHash };
}

const itemInLog = find(changelog, findTest);
const appliedAt = itemInLog ? itemInLog.appliedAt.toJSON() : "PENDING";
return useFileHash ? { fileName, fileHash, appliedAt } : { fileName, appliedAt };
const appliedAt = itemInLog ? itemInLog[dateField].toJSON() : "PENDING";
return {
[nameField]: migrationName,
[dateField]: appliedAt,
file: fileName,
...(useFileHash && { fileHash }),
};
}));

return statusTable;
};
42 changes: 32 additions & 10 deletions lib/actions/up.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
/* eslint no-console: 0 */
const _ = require("lodash");
const pEachSeries = require("p-each-series");
const { promisify } = require("util");
const fnArgs = require('fn-args');
const fnArgs = require("fn-args");

const status = require("./status");
const config = require("../env/config");
const migrationsDir = require("../env/migrationsDir");
const hasCallback = require('../utils/has-callback');
const getName = require('../utils/name');

module.exports = async (db, client) => {
const statusItems = await status(db);
const pendingItems = _.filter(statusItems, { appliedAt: "PENDING" });
const configObject = await config.read()
const {
changelogCollectionName,
useFileHash,
dateField,
nameField,
} = configObject;

const pendingItems = _.filter(statusItems, { [dateField]: "PENDING" });
const migrated = [];

const migrateItem = async item => {
console.info(`Migrating ${item.file}`);
const timeTaken = `${item.file} was successfully migrated`;
console.time(timeTaken);
try {
const migration = await migrationsDir.loadMigration(item.fileName);
const migration = await migrationsDir.loadMigration(item.file);
const up = hasCallback(migration.up) ? promisify(migration.up) : migration.up;

if (hasCallback(migration.up) && fnArgs(migration.up).length < 3) {
Expand All @@ -27,27 +40,36 @@ module.exports = async (db, client) => {

} catch (err) {
const error = new Error(
`Could not migrate up ${item.fileName}: ${err.message}`
`Could not migrate up ${item.file}: ${err.message}`
);
error.stack = err.stack;
error.migrated = migrated;
throw error;
}

const { changelogCollectionName, useFileHash } = await config.read();
const changelogCollection = db.collection(changelogCollectionName);

const { fileName, fileHash } = item;
const { file, fileHash } = item;
const migrationName = getName(configObject, file);
const appliedAt = new Date();

try {
await changelogCollection.insertOne(useFileHash === true ? { fileName, fileHash, appliedAt } : { fileName, appliedAt });
await changelogCollection.insertOne({
[nameField]: migrationName,
[dateField]: appliedAt,
...(useFileHash === true && { fileHash }),
});
} catch (err) {
throw new Error(`Could not update changelog: ${err.message}`);
}
migrated.push(item.fileName);
migrated.push(item.file);
console.timeEnd(timeTaken);
};

await pEachSeries(pendingItems, migrateItem);
if (pendingItems.length)
await pEachSeries(pendingItems, migrateItem);
else
console.info('Nothing to migrate');


return migrated;
};
18 changes: 16 additions & 2 deletions lib/env/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const { get } = require("lodash");
const moduleLoader = require('../utils/module-loader');

const DEFAULT_CONFIG_FILE_NAME = "migrate-mongo-config.js";
const DEFAULT_NAME_FIELD = 'fileName';
const DEFAULT_DATE_FIELD = 'appliedAt';

let customConfigContent = null;

Expand Down Expand Up @@ -57,17 +59,29 @@ module.exports = {
return path.basename(getConfigPath());
},

setConfigDefaults(config) {
if (!config.nameField)
config.nameField = DEFAULT_NAME_FIELD;

if (!config.dateField)
config.dateField = DEFAULT_DATE_FIELD;

return config
},

async read() {
if (customConfigContent) {
return customConfigContent;
}
const configPath = getConfigPath();
try {
return await Promise.resolve(moduleLoader.require(configPath));
const config = await Promise.resolve(moduleLoader.require(configPath));
return this.setConfigDefaults(config)
} catch (e) {
if (e.code === 'ERR_REQUIRE_ESM') {
const loadedImport = await moduleLoader.import(url.pathToFileURL(configPath));
return loadedImport.default
const config = loadedImport.default
return this.setConfigDefaults(config)
}
throw e;
}
Expand Down
9 changes: 9 additions & 0 deletions lib/utils/name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = (config, fileName) => {
let migrationName = fileName;
if (config.namePrefix)
migrationName = `${config.namePrefix}${migrationName}`;
if (config.nameWithoutExtension)
migrationName = migrationName.substring(0, migrationName.lastIndexOf('.')) || migrationName;

return migrationName
}
12 changes: 12 additions & 0 deletions samples/commonjs/migrate-mongo-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ const config = {
// The mongodb collection where the applied changes are stored. Only edit this when really necessary.
changelogCollectionName: "changelog",

// Field in collection to store migration name
nameField: 'fileName',

// Prefix for migration name
namePrefix: '',

// Whether name should include file extension
nameWithoutExtension: false,

// Field in collection to store migration applied date
dateField: 'appliedAt',

// The file extension to create migrations and search for in migration dir
migrationFileExtension: ".js",

Expand Down
8 changes: 7 additions & 1 deletion test/actions/down.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ describe("down", () => {
return sinon.stub().returns(
Promise.resolve([
{
file: "20160609113224-first_migration.js",
fileName: "20160609113224-first_migration.js",
appliedAt: new Date()
},
{
file: "20160609113225-last_migration.js",
fileName: "20160609113225-last_migration.js",
appliedAt: new Date()
}
Expand All @@ -31,7 +33,11 @@ describe("down", () => {
function mockConfig() {
return {
shouldExist: sinon.stub().returns(Promise.resolve()),
read: sinon.stub().returns({ changelogCollectionName: "changelog" })
read: sinon.stub().returns({
changelogCollectionName: "changelog",
dateField: "appliedAt",
nameField: "fileName",
})
};
}

Expand Down
Loading