Skip to content

Commit bf95edb

Browse files
committed
initial commit
1 parent 1455dc5 commit bf95edb

File tree

6 files changed

+197
-0
lines changed

6 files changed

+197
-0
lines changed

.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

index.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
'use strict';
2+
3+
const migrationSchema = require('./src/schemas/migrationSchema');
4+
const mongoose = require('mongoose');
5+
6+
let Migration = null;
7+
let migration = null;
8+
9+
const mongooseObjToOp = new WeakMap();
10+
11+
exports._initMigrationFramework = function _initMigrationFramework(conn) {
12+
conn = conn || mongoose.connection;
13+
14+
if (conn.models._Migration) {
15+
return;
16+
}
17+
18+
Migration = Migration || conn.model('_Migration', migrationSchema, '_migrations');
19+
20+
mongoose.plugin(function(schema) {
21+
schema.pre(['updateOne', 'updateMany', 'replaceOne'], async function() {
22+
migration.operations.push({
23+
modelName: this.model.modelName,
24+
opName: this.op,
25+
parameters: {
26+
filter: this.getFilter(),
27+
update: this.getUpdate()
28+
}
29+
});
30+
mongooseObjToOp.set(this, migration.operations[migration.operations.length - 1]);
31+
32+
await migration.save();
33+
});
34+
35+
schema.post(['updateOne', 'updateMany', 'replaceOne'], async function(res) {
36+
const op = mongooseObjToOp.get(this);
37+
console.log('X', op, res);
38+
if (op == null) {
39+
return;
40+
}
41+
op.endedAt = new Date();
42+
op.status = 'complete';
43+
op.result = res;
44+
45+
await migration.save();
46+
});
47+
});
48+
};
49+
50+
exports.startMigration = async function startMigration() {
51+
migration = await Migration.create({});
52+
53+
return migration;
54+
};
55+
56+
exports.endMigration = async function endMigration(error) {
57+
if (error) {
58+
migration.status = 'error';
59+
migration.error.message = error.message;
60+
migration.error.stack = error.stack;
61+
} else {
62+
migration.status = 'complete';
63+
}
64+
migration.endedAt = new Date();
65+
await migration.save();
66+
67+
migration = null;
68+
};
69+
70+
exports.eachAsync = async function eachAsync(model, options, fn) {
71+
if (typeof options === 'function') {
72+
fn = options;
73+
options = null;
74+
}
75+
};

package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "@mongoosejs/migrations",
3+
"version": "0.0.1",
4+
"scripts": {
5+
"test": "mocha test/*.test.js"
6+
},
7+
"peerDependencies": {
8+
"mongoose": "6.x"
9+
},
10+
"devDependencies": {
11+
"mocha": "9.2.1",
12+
"mongoose": "6.x"
13+
}
14+
}

src/schemas/migrationSchema.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict';
2+
3+
const mongoose = require('mongoose');
4+
5+
module.exports = new mongoose.Schema({
6+
status: {
7+
type: String,
8+
required: true,
9+
enum: ['not_started', 'in_progress', 'error', 'complete'],
10+
default: 'in_progress'
11+
},
12+
runId: {
13+
type: 'ObjectId',
14+
required: true,
15+
default: () => new mongoose.Types.ObjectId()
16+
},
17+
operations: [{
18+
modelName: {
19+
type: String,
20+
required: true
21+
},
22+
opName: {
23+
type: String,
24+
required: true
25+
},
26+
userFunctionName: {
27+
type: String
28+
},
29+
status: {
30+
type: String,
31+
required: true,
32+
enum: ['not_started', 'in_progress', 'error', 'complete'],
33+
default: 'in_progress'
34+
},
35+
error: {
36+
message: String,
37+
stack: String
38+
},
39+
startedAt: {
40+
type: Date,
41+
required: true,
42+
default: () => Date.now()
43+
},
44+
endedAt: {
45+
type: Date
46+
},
47+
firstSeenSortKey: 'Mixed',
48+
lastSeenSortKey: 'Mixed',
49+
parameters: 'Mixed',
50+
result: 'Mixed'
51+
}]
52+
}, { timestamps: true });

test/setup.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
3+
const { before } = require('mocha');
4+
const migrations = require('../');
5+
const mongoose = require('mongoose');
6+
7+
console.log('Init?');
8+
migrations._initMigrationFramework();
9+
10+
before(async function() {
11+
await mongoose.connect('mongodb://localhost:27017/test_migrations');
12+
});
13+
14+
after(async function() {
15+
await mongoose.disconnect();
16+
});

test/updates.test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const { before, describe, it, afterEach, beforeEach } = require('mocha');
5+
const mongoose = require('mongoose');
6+
const migrations = require('../');
7+
8+
describe('updates', function() {
9+
let TestModel;
10+
let migration;
11+
12+
before(function() {
13+
console.log('Create new model');
14+
TestModel = mongoose.model('Test', mongoose.Schema({
15+
name: String,
16+
email: String
17+
}));
18+
});
19+
20+
beforeEach(async function() {
21+
migration = await migrations.startMigration();
22+
});
23+
24+
afterEach(() => migrations.endMigration());
25+
26+
it('stores the update result if succeeded', async function() {
27+
await TestModel.collection.insertOne({ name: 'John Smith' });
28+
await TestModel.updateOne({ name: 'John Smith' }, { name: 'John Smythe' });
29+
30+
assert.equal(migration.operations.length, 1);
31+
assert.deepEqual(migration.operations[0].result, {
32+
acknowledged: true,
33+
matchedCount: 1,
34+
modifiedCount: 1,
35+
upsertedCount: 0,
36+
upsertedId: null
37+
});
38+
});
39+
});

0 commit comments

Comments
 (0)