diff --git a/README.md b/README.md index 4067557..3c9e9b9 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Usage: migrate-mongo [options] [command] Options: + -c, --custom specify a custom migration file (only for up) -h, --help output usage information -V, --version output the version number ```` diff --git a/bin/migrate-mongo.js b/bin/migrate-mongo.js index f002be0..8b8f580 100755 --- a/bin/migrate-mongo.js +++ b/bin/migrate-mongo.js @@ -58,6 +58,7 @@ program program .command("up") .description("run all pending database migrations") + .option("-c --custom ", "run a custom migration file") .option("-f --file ", "use a custom config file") .action(options => { global.options = options; diff --git a/lib/actions/up.js b/lib/actions/up.js index f053c82..aabf6e7 100644 --- a/lib/actions/up.js +++ b/lib/actions/up.js @@ -1,22 +1,25 @@ 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 hasCallback = require("../utils/has-callback"); module.exports = async (db, client) => { const statusItems = await status(db); const pendingItems = _.filter(statusItems, { appliedAt: "PENDING" }); const migrated = []; - const migrateItem = async item => { + // console.log(pendingItems); + const migrateItem = async (item) => { try { const migration = await migrationsDir.loadMigration(item.fileName); - const up = hasCallback(migration.up) ? promisify(migration.up) : migration.up; + const up = hasCallback(migration.up) + ? promisify(migration.up) + : migration.up; if (hasCallback(migration.up) && fnArgs(migration.up).length < 3) { // support old callback-based migrations prior to migrate-mongo 7.x.x @@ -24,7 +27,6 @@ module.exports = async (db, client) => { } else { await up(db, client); } - } catch (err) { const error = new Error( `Could not migrate up ${item.fileName}: ${err.message}` @@ -33,20 +35,35 @@ module.exports = async (db, client) => { throw error; } - const { changelogCollectionName } = await config.read(); - const changelogCollection = db.collection(changelogCollectionName); + if (item.appliedAt != "CUSTOM") + { + // console.log("writing", item.appliedAt); + const { changelogCollectionName } = await config.read(); + const changelogCollection = db.collection(changelogCollectionName); - const { fileName } = item; - const appliedAt = new Date(); + const { fileName } = item; + const appliedAt = new Date(); - try { - await changelogCollection.insertOne({ fileName, appliedAt }); - } catch (err) { - throw new Error(`Could not update changelog: ${err.message}`); + try { + await changelogCollection.insertOne({ fileName, appliedAt }); + } catch (err) { + throw new Error(`Could not update changelog: ${err.message}`); + } } + migrated.push(item.fileName); }; - await pEachSeries(pendingItems, migrateItem); + // console.log("some", global.options); + if (global.options.custom) { + await migrateItem( + { fileName: global.options.custom, appliedAt: "CUSTOM" }, + false + ); + } else { + // console.log("all"); + await pEachSeries(pendingItems, migrateItem); + } + return migrated; }; diff --git a/lib/env/database.js b/lib/env/database.js index 70ce8fd..6fc03d6 100644 --- a/lib/env/database.js +++ b/lib/env/database.js @@ -8,7 +8,7 @@ module.exports = { const url = _.get(configContent, "mongodb.url"); const databaseName = _.get(configContent, "mongodb.databaseName"); const options = _.get(configContent, "mongodb.options"); - +console.log("config", configContent); if (!url) { throw new Error("No `url` defined in config file!"); } @@ -25,4 +25,5 @@ module.exports = { db, }; } + }; diff --git a/samples/migrations/20200911163740-desc2.js b/samples/migrations/20200911163740-desc2.js new file mode 100644 index 0000000..f893136 --- /dev/null +++ b/samples/migrations/20200911163740-desc2.js @@ -0,0 +1,14 @@ +module.exports = { + async up(db, client) { + // TODO write your migration here. + // See https://github.com/seppevs/migrate-mongo/#creating-a-new-migration-script + // Example: + // await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: true}}); + }, + + async down(db, client) { + // TODO write the statements to rollback your migration (if possible) + // Example: + // await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: false}}); + } +}; diff --git a/samples/migrations/dev2.js b/samples/migrations/dev2.js new file mode 100644 index 0000000..f893136 --- /dev/null +++ b/samples/migrations/dev2.js @@ -0,0 +1,14 @@ +module.exports = { + async up(db, client) { + // TODO write your migration here. + // See https://github.com/seppevs/migrate-mongo/#creating-a-new-migration-script + // Example: + // await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: true}}); + }, + + async down(db, client) { + // TODO write the statements to rollback your migration (if possible) + // Example: + // await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: false}}); + } +}; diff --git a/test/actions/up.test.js b/test/actions/up.test.js index 8508122..4cc17bf 100644 --- a/test/actions/up.test.js +++ b/test/actions/up.test.js @@ -13,6 +13,7 @@ describe("up", () => { let firstPendingMigration; let secondPendingMigration; + let firstCustomMigration; let changelogCollection; function mockStatus() { @@ -26,6 +27,10 @@ describe("up", () => { fileName: "20160606093207-second_applied_migration.js", appliedAt: new Date() }, + { + fileName: "20160608060210-first_custom_migration.js", + appliedAt: "CUSTOM" + }, { fileName: "20160607173840-first_pending_migration.js", appliedAt: "PENDING" @@ -56,6 +61,9 @@ describe("up", () => { mock.loadMigration .withArgs("20160608060209-second_pending_migration.js") .returns(Promise.resolve(secondPendingMigration)); + mock.loadMigration + .withArgs("20160608060210-first_custom_migration.js") + .returns(Promise.resolve(firstCustomMigration)); return mock; } @@ -95,6 +103,7 @@ describe("up", () => { beforeEach(() => { firstPendingMigration = mockMigration(); secondPendingMigration = mockMigration(); + firstCustomMigration = mockMigration(); changelogCollection = mockChangelogCollection(); status = mockStatus(); @@ -104,6 +113,8 @@ describe("up", () => { client = mockClient(); up = loadUpWithInjectedMocks(); + + global.options={}; }); it("should fetch the status", async () => { @@ -130,6 +141,13 @@ describe("up", () => { sinon.assert.callOrder(firstPendingMigration.up, secondPendingMigration.up); }); + it("should be able to run a custom migration", async () => { + global.options = { custom: "20160608060210-first_custom_migration.js" }; + await up(db); + expect(firstCustomMigration.up.called).to.equal(true); + expect(changelogCollection.insertOne.called).to.equal(false); + }); + it("should be able to upgrade callback based migration that has both the `db` and `client` args", async () => { firstPendingMigration = { up(theDb, theClient, callback) {