Skip to content

Commit

Permalink
Added the ability to have dependencies for migrations.
Browse files Browse the repository at this point in the history
  • Loading branch information
durango committed Jan 6, 2014
1 parent ba70142 commit 9840084
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 98 deletions.
72 changes: 69 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ Migrate SequelizeJS migrations without SequelizeMeta table dependency.

## Examples

```$: sequelize-migrator -c ../../global_config.json -p ../migrations up```
```
$: sequelize-migrator -c ../../global_config.json -p ../migrations up
$: sequelize-migrator -c ../../global_config.json -p ../migrations down
$: sequelize-migrator -c ../../global_config.json up # looks for ./migrations within path
```

## Config File Example

```
```js
module.exports = {
username: process.env.SEQ_USER || '',
password: process.env.SEQ_PW || null,
Expand All @@ -34,4 +38,66 @@ module.exports = {
port: process.env.SEQ_PORT || [dialect specific]
dialect: process.env.SEQ_DIALECT || '',
}
```
```

## Dependencies

Dependencies can be added via a "deps" array key within the migration files like so...

### [timestamp]-userTable.js
```js
module.exports = {
up: function(migration, DataTypes, done) {
migration.addColumn('users', 'email', DataTypes.STRING).complete(done);
},
down: function(migration, DataTypes, done) {
migration.removeColumn('users', 'email').complete(done);
}
}
```

### [timestamp]-usersAddEmail.js
```js
module.exports = {
up: function(migration, DataTypes, done) {
migration.addColumn('users', 'email', DataTypes.STRING).complete(done);
},
down: function(migration, DataTypes, done) {
migration.removeColumn('users', 'email').complete(done);
}
}
```

### [timestamp]-usersAddTest.js
**Note:** [timestamp] is *before* usersAddEmail
```js
module.exports = {
deps: [
'20140105151356-usersAddEmail'
],
up: function(migration, DataTypes, done) {
migration.addColumn('users', 'test', DataTypes.STRING).complete(done);
},
down: function(migration, DataTypes, done) {
migration.removeColumn('users', 'test').complete(done);
}
}
```

### [timestamp]-usersAddTest2.js
**Note:** [timestamp] is *before* usersAddTest
```js
module.exports = {
deps: [
'20140105151200-usersAddTest'
],
up: function(migration, DataTypes, done) {
migration.addColumn('users', 'test2', DataTypes.STRING).complete(done);
},
down: function(migration, DataTypes, done) {
migration.removeColumn('users', 'test2').complete(done);
}
}
```

Dependencies are matched on a case-sensitive regex. Feel free to shorten dependency names such as ```20140105151200-usersAddTest``` into ```usersAddTest```. This will fetch all migrations that match "usersAddTest".
141 changes: 90 additions & 51 deletions bin/sequelize-migrator
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var path = require('path')
, Migration = require(path.resolve(path.join(__dirname, '..', 'node_modules', 'sequelize', 'lib', 'migration')))
, Utils = require(path.resolve(path.join(__dirname, '..', 'node_modules', 'sequelize', 'lib', 'utils')))
, lib = require(path.resolve(path.join(__dirname, '..', 'index')))
, deptree = require('deptree')
, pkgJson = require(path.resolve(path.join(__dirname, '..', 'package.json')));

program
Expand Down Expand Up @@ -57,70 +58,108 @@ var migrator = sequelize.getMigrator({
options.method = cmd;

return new Utils.CustomEventEmitter(function (emitter) {
var chainer = new Utils.QueryChainer()

migrations
.map(function (migration) {
// migrations deals with paths...in a retarded manner..
migration.path = path.resolve(path.join(program.path, migration.filename));
return migration;
})
.forEach(function (migration) {
var migrationTime;

chainer.add(migration, 'execute', [options], {
before: function(migration) {
console.log('Running migration file ' + migration.filename);
migrationTime = process.hrtime()
},

after: function(migration) {
migrationTime = process.hrtime(migrationTime)
migrationTime = Math.round( (migrationTime[0] * 1000) + (migrationTime[1] / 1000000));
console.log('Completed in ' + migrationTime + 'ms')
},

success: function(migration, callback) {
if (options.method === 'down') {
fs.renameSync(migration.path, migration.path.replace(/\.done$/, ''));
callback();
} else {
fs.renameSync(migration.path, (migration.path + '.done'));
callback();
}
}
})
})

chainer
.runSerially({ skipOnError: true })
.success(function() { emitter.emit('success', null) })
.error(function(err) { emitter.emit('error', err) })
var chainer = new Utils.QueryChainer()

migrations
.map(function (migration) {
// migrations deals with paths...in a retarded manner..
migration.path = path.resolve(path.join(program.path, migration.filename));
return migration;
})
.forEach(function (migration) {
var migrationTime;

chainer.add(migration, 'execute', [options], {
before: function(migration) {
console.log('Running migration file ' + migration.filename);
migrationTime = process.hrtime()
},

after: function(migration) {
migrationTime = process.hrtime(migrationTime)
migrationTime = Math.round( (migrationTime[0] * 1000) + (migrationTime[1] / 1000000));
console.log('Completed in ' + migrationTime + 'ms')
},

success: function(migration, callback) {
if (options.method === 'down') {
fs.renameSync(migration.path, migration.path.replace(/\.done$/, ''));
callback();
} else {
fs.renameSync(migration.path, (migration.path + '.done'));
callback();
}
}
})
})

chainer
.runSerially({ skipOnError: true })
.success(function() { emitter.emit('success', null) })
.error(function(err) { emitter.emit('error', err) })
}).run()
}

var files = fs.readdirSync(program.path).filter(function (file) {
var depTree = new deptree()
, files = fs.readdirSync(program.path);

files.forEach(function (file, idx) {
var f = require(path.resolve(path.join(program.path, file)))
, deps = [];

if (f.hasOwnProperty('deps')) {
f.deps.forEach(function (dep) {
files.forEach(function (_migrate) {
if ((new RegExp(dep)).test(_migrate) && _migrate !== file) {
deps.push(_migrate);
}
});
});
}

if (deps.length > 0) {
depTree.add(file, deps);
} else {
depTree.add(file);
}
});

var fileTree = depTree.resolve();

var base = fileTree.filter(function (tree) {
return depTree.nodes[tree].length < 1;
})
.filter(function (file) {
return ((cmd === "up" ? /\.js$/ : /\.js\.done$/)).test(file);
})
.sort(function (a, b) {
return parseInt(a.split('-')[0]) - parseInt(b.split('-')[0]);
});

var inject = fileTree.filter(function (tree) {
return base.indexOf(tree) === -1;
});

var resolved = base.concat(inject);

if (cmd === "down") {
resolved.reverse();
}

resolved = resolved.filter(function (file) {
return ((cmd === "up" ? /\.js$/ : /\.js\.done$/)).test(file);
})
.map(function (file) {
return new Migration(migrator, path.resolve(path.join(program.path, file)));
})
.sort(function (a, b){
return parseInt(a.filename.split('-')[0]) - parseInt(b.filename.split('-')[0])
});

if (files.length < 1) {
process.stdout.write('There are currently no pending migrations.');
if (resolved.length < 1) {
console.log('There are currently no pending migrations.');
process.exit(0);
}

if (cmd === "down") {
files.reverse();
}

console.log('Running migrations...');

migrate(files, { method: cmd }).success(function() {
migrate(resolved, { method: cmd }).success(function() {
console.log('Migrations have run successfully!')
process.exit(0);
})
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sequelize-migrator",
"version": "1.0.0",
"description": "Migrate SequelizeJS migrations without SequelizeMeta table dependency.",
"description": "Migrate SequelizeJS migrations without SequelizeMeta table dependency and depdency management.",
"main": "index.js",
"scripts": {
"test": "make all"
Expand All @@ -14,7 +14,8 @@
"mysql": "~2.0.0-rc2",
"mariasql": "git://github.com/mscdex/node-mariasql.git",
"sqlite3": "~2.1.19",
"pg": "~2.10.0"
"pg": "~2.10.0",
"deptree": "~0.1.0"
},
"devDependencies": {
"chai": "~1.8.1",
Expand Down
11 changes: 11 additions & 0 deletions test/assets/20140105151199-depTest2-assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
deps: [
'20140105151200-depTest-assets'
],
up: function(migration, DataTypes, done) {
migration.addColumn('userAssets', 'test2', DataTypes.STRING).complete(done);
},
down: function(migration, DataTypes, done) {
migration.removeColumn('userAssets', 'test2').complete(done);
}
}
11 changes: 11 additions & 0 deletions test/assets/20140105151200-depTest-assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
deps: [
'20140105151356-usersAddEmail-assets'
],
up: function(migration, DataTypes, done) {
migration.addColumn('userAssets', 'test', DataTypes.STRING).complete(done);
},
down: function(migration, DataTypes, done) {
migration.removeColumn('userAssets', 'test').complete(done);
}
}
Loading

0 comments on commit 9840084

Please sign in to comment.