Skip to content

Commit 748121d

Browse files
committed
feat: allow instantiation of instance to call methods with config set via api
1 parent a297659 commit 748121d

25 files changed

+913
-503
lines changed

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,10 @@ node_modules
77

88
# Istanbul test coverage
99
coverage
10-
.nyc_output
10+
.nyc_output
11+
12+
// .npmignore
13+
/src
14+
15+
*.log
16+
/node_modules

bin/migrate-mongo.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ program
3333
.init()
3434
.then(() =>
3535
console.log(
36-
`Initialization successful. Please edit the generated \`${migrateMongo.config.getConfigFilename()}\` file`
36+
`Initialization successful. Please edit the generated \`${migrateMongo.configFile.getConfigFilename()}\` file`
3737
)
3838
)
3939
.catch(err => handleError(err))
@@ -48,7 +48,7 @@ program
4848
migrateMongo
4949
.create(description)
5050
.then(fileName =>
51-
migrateMongo.config.read().then(config => {
51+
migrateMongo.configFile.read().then(config => {
5252
console.log(`Created: ${config.migrationsDir}/${fileName}`);
5353
})
5454
)

lib/MigrateMongo.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const up = require("./instance_methods/up");
2+
const down = require("./instance_methods/down");
3+
const status = require("./instance_methods/status");
4+
const database = require("./instance_methods/database");
5+
const validateConfig = require("./utils/validateConfig");
6+
7+
class MigrateMongo {
8+
constructor(config) {
9+
if (!config) {
10+
throw new Error("No config passed to MigrateMongo instance");
11+
}
12+
validateConfig(config);
13+
14+
this.config = config;
15+
16+
const statusWithConfig = status(config);
17+
18+
this.up = up(config, statusWithConfig);
19+
this.down = down(config, statusWithConfig);
20+
this.status = statusWithConfig;
21+
this.database = database(config);
22+
}
23+
}
24+
25+
module.exports = MigrateMongo;

lib/actions/status.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
const { find } = require("lodash");
22
const migrationsDir = require("../env/migrationsDir");
33
const configFile = require("../env/configFile");
4+
const getJavaScriptFilesFromPath = require("../utils/getJavaScriptFilesFromPath");
45

56
module.exports = async db => {
67
await migrationsDir.shouldExist();
78
await configFile.shouldExist();
8-
const fileNames = await migrationsDir.getFileNames();
9+
10+
const migrationsDirPath = migrationsDir.resolveMigrationsDirPath();
11+
const fileNames = await getJavaScriptFilesFromPath(migrationsDirPath);
912

1013
const config = await configFile.read();
1114
const collectionName = config.changelogCollectionName;

lib/env/database.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const { MongoClient } = require("mongodb");
22
const _ = require("lodash");
33
const configFile = require("./configFile");
4+
const validateConfig = require("../utils/validateConfig");
45

56
module.exports = {
67
async connect() {
@@ -9,21 +10,9 @@ module.exports = {
910
const databaseName = _.get(config, "mongodb.databaseName");
1011
const options = _.get(config, "mongodb.options");
1112

12-
if (!url) {
13-
throw new Error("No `url` defined in config file!");
14-
}
13+
validateConfig(config);
1514

16-
if (!databaseName) {
17-
throw new Error(
18-
"No `databaseName` defined in config file! This is required since migrate-mongo v3. " +
19-
"See https://github.com/seppevs/migrate-mongo#initialize-a-new-project"
20-
);
21-
}
22-
23-
const client = await MongoClient.connect(
24-
url,
25-
options
26-
);
15+
const client = await MongoClient.connect(url, options);
2716

2817
const db = client.db(databaseName);
2918
db.close = client.close;

lib/env/migrationsDir.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const fs = require("fs-extra");
22
const path = require("path");
33
const configFile = require("./configFile");
4+
const getAbsoluteFilePath = require("../utils/getAbsoluteFilePath");
45

56
const DEFAULT_MIGRATIONS_DIR_NAME = "migrations";
67

@@ -18,15 +19,14 @@ async function resolveMigrationsDirPath() {
1819
migrationsDir = DEFAULT_MIGRATIONS_DIR_NAME;
1920
}
2021

21-
if (path.isAbsolute(migrationsDir)) {
22-
return migrationsDir;
23-
}
24-
return path.join(process.cwd(), migrationsDir);
22+
return getAbsoluteFilePath(migrationsDir);
2523
}
2624

2725
module.exports = {
2826
resolve: resolveMigrationsDirPath,
2927

28+
resolveMigrationsDirPath,
29+
3030
async shouldExist() {
3131
const migrationsDir = await resolveMigrationsDirPath();
3232
try {
@@ -52,12 +52,6 @@ module.exports = {
5252
}
5353
},
5454

55-
async getFileNames() {
56-
const migrationsDir = await resolveMigrationsDirPath();
57-
const files = await fs.readdir(migrationsDir);
58-
return files.filter(file => path.extname(file) === ".js");
59-
},
60-
6155
async loadMigration(fileName) {
6256
const migrationsDir = await resolveMigrationsDirPath();
6357
return require(path.join(migrationsDir, fileName)); // eslint-disable-line

lib/instance_methods/database.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const { MongoClient } = require("mongodb");
2+
3+
const database = config => ({
4+
connect: async () => {
5+
const { url, databaseName, options } = config.mongodb;
6+
7+
if (!url) {
8+
throw new Error("No `url` defined in config file!");
9+
}
10+
11+
if (!databaseName) {
12+
throw new Error(
13+
"No `databaseName` defined in config file! This is required since migrate-mongo v3. " +
14+
"See https://github.com/seppevs/migrate-mongo#initialize-a-new-project"
15+
);
16+
}
17+
18+
const client = await MongoClient.connect(url, options);
19+
20+
const db = client.db(databaseName);
21+
db.close = client.close;
22+
return db;
23+
}
24+
});
25+
26+
module.exports = database;

lib/instance_methods/down.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const _ = require("lodash");
2+
const fnArgs = require("fn-args");
3+
const { promisify } = require("util");
4+
const loadMigration = require("../utils/loadMigration");
5+
6+
module.exports = (config, status) => async db => {
7+
const downgraded = [];
8+
const statusItems = await status(db, config);
9+
const appliedItems = statusItems.filter(item => item.appliedAt !== "PENDING");
10+
const lastAppliedItem = _.last(appliedItems);
11+
12+
if (lastAppliedItem) {
13+
try {
14+
const migration = loadMigration(
15+
config.migrationDir,
16+
lastAppliedItem.fileName
17+
);
18+
19+
const args = fnArgs(migration.down);
20+
const down = args.length > 1 ? promisify(migration.down) : migration.down;
21+
await down(db);
22+
} catch (err) {
23+
throw new Error(
24+
`Could not migrate down ${lastAppliedItem.fileName}: ${err.message}`
25+
);
26+
}
27+
28+
const collectionName = config.changelogCollectionName;
29+
const collection = db.collection(collectionName);
30+
try {
31+
await collection.deleteOne({ fileName: lastAppliedItem.fileName });
32+
downgraded.push(lastAppliedItem.fileName);
33+
} catch (err) {
34+
throw new Error(`Could not update changelog: ${err.message}`);
35+
}
36+
}
37+
38+
return downgraded;
39+
};

lib/instance_methods/status.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const { find } = require("lodash");
2+
const getJavaScriptFilesFromPath = require("../utils/getJavaScriptFilesFromPath");
3+
const getAbsoluteFilePath = require("../utils/getAbsoluteFilePath");
4+
5+
const status = config => async db => {
6+
const migrationsDir = getAbsoluteFilePath(config.migrationsDir);
7+
const fileNames = await getJavaScriptFilesFromPath(migrationsDir);
8+
9+
let collectionName = "changelog";
10+
11+
if (config.changelogCollectionName) {
12+
collectionName = config.changelogCollectionName;
13+
} else {
14+
collectionName = "changelog";
15+
console.warn(
16+
'No changelogCollectionName found in confg - defaulting to "changelog"'
17+
);
18+
}
19+
20+
const collection = db.collection(collectionName);
21+
const changelog = await collection.find({}).toArray();
22+
23+
const statusTable = fileNames.map(fileName => {
24+
const itemInLog = find(changelog, { fileName });
25+
const appliedAt = itemInLog ? itemInLog.appliedAt.toJSON() : "PENDING";
26+
return { fileName, appliedAt };
27+
});
28+
29+
return statusTable;
30+
};
31+
32+
module.exports = status;

lib/instance_methods/up.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const _ = require("lodash");
2+
const pEachSeries = require("p-each-series");
3+
const fnArgs = require("fn-args");
4+
const { promisify } = require("util");
5+
const loadMigration = require("../utils/loadMigration");
6+
7+
module.exports = (config, status) => async db => {
8+
const statusItems = await status(db, config);
9+
const pendingItems = _.filter(statusItems, { appliedAt: "PENDING" });
10+
const migrated = [];
11+
12+
const migrateItem = async item => {
13+
try {
14+
const migration = loadMigration(config.migrationsDir, item.fileName);
15+
const args = fnArgs(migration.up);
16+
const up = args.length > 1 ? promisify(migration.up) : migration.up;
17+
await up(db);
18+
} catch (err) {
19+
const error = new Error(
20+
`Could not migrate up ${item.fileName}: ${err.message}`
21+
);
22+
error.migrated = migrated;
23+
throw error;
24+
}
25+
26+
let collectionName;
27+
if (config.changelogCollectionName) {
28+
collectionName = config.changelogCollectionName;
29+
} else {
30+
collectionName = "changelog";
31+
console.warn(
32+
'No changelogCollectionName found in confg - defaulting to "changelog"'
33+
);
34+
}
35+
36+
const collection = db.collection(collectionName);
37+
38+
const { fileName } = item;
39+
const appliedAt = new Date();
40+
41+
try {
42+
await collection.insertOne({ fileName, appliedAt });
43+
} catch (err) {
44+
throw new Error(`Could not update changelog: ${err.message}`);
45+
}
46+
migrated.push(item.fileName);
47+
};
48+
49+
await pEachSeries(pendingItems, migrateItem);
50+
return migrated;
51+
};

0 commit comments

Comments
 (0)