Skip to content

Instantly share code, notes, and snippets.

@ssteffl
Created September 1, 2015 15:18
Show Gist options
  • Save ssteffl/132afcdc7e1c296b7f51 to your computer and use it in GitHub Desktop.
Save ssteffl/132afcdc7e1c296b7f51 to your computer and use it in GitHub Desktop.
#!/usr/bin/env node
//INTERFACE CODE
module.exports = (function(){
var fs = require('fs'),
path = require('path'),
Promise = require('bluebird'),
Transaction = require('sequelize/lib/transaction'),
Sequelize = require("sequelize"),
NOT_OPENED_ERROR = 'db not opened',
NOT_CLOSED_ERROR = 'db not closed',
STATES = {
CLOSED:1,
OPENING:2,
OPEN:3,
CLOSING:4
},
state = STATES.CLOSED,
instance = null;
Transaction.prototype.cleanup = function() { //bug in sequelize cleanup does not close transaction connections
var cls = this.sequelize.constructor.cls;
if(cls && cls.get('transaction') === this) cls.set('transaction', null);
return this.sequelize.connectionManager.releaseConnection(this.connection);
};
return function(config){
if(instance) return instance;
else {
instance = {
_sequelize: null,
_models: {},
open: function(){
if(state != STATES.CLOSED) return Promise.reject(NOT_CLOSED_ERROR);
else {
state = STATES.OPENING;
instance._sequelize = new Sequelize(null, null, null, config.dbConfig);
instance._models = {};
fs.readdirSync(path.resolve(__dirname, 'model')).forEach(function(file) {
if(fs.statSync(path.resolve(__dirname, 'model', file)).isDirectory()) return;
//concat it because require could return multiple models in an array
var models = [].concat(require(path.resolve(__dirname, 'model', file))(instance._sequelize, config));
models.forEach(function(model){ instance._models[model.name] = model; });
});
Object.keys(instance._models).forEach(function(modelName){
if("associate" in instance._models[modelName]) instance._models[modelName].associate(instance._models);
});
return instance._sequelize.sync()
.then(function(){ state = STATES.OPEN; })
.catch(function(reason){
state = STATES.ERROR;
instance._sequelize = null;
instance._models = {};
return Promise.reject(reason);
});
}
},
close: function(){
if(state != STATES.OPEN) return Promise.reject(NOT_OPENED_ERROR);
return instance._sequelize.connectionManager.getConnection({uuid:'default'}).then(function(cxn){
cxn.close();
instance._sequelize = null;
instance._models = {};
state = STATES.CLOSED;
});
},
query: function(){ return instance._sequelize.query.apply(instance._sequelize, arguments); },
transaction: function(){ return instance._sequelize.transaction.apply(instance._sequelize, arguments); },
get: function(modelName){ return instance._models[modelName] || null; },
getAll: function(modelName){ return Object.keys(instance._models).map(function(key){ return instance._models[key]; }); }
};
return instance;
}
};
}());
#!/usr/bin/env node
//SEQUELIZE CONFIG
config.dbConfig = {
dialect: 'sqlite',
storage: mkPath(config.fsConfig.fsDataDir, 'db.sqlite3'),
pool: false,
logging: false,
define: {
timestamps: false,
paranoid: false,
freezeTableName: true,
hooks: {
beforeBulkCreate: function(records, options){ if(!options.individualHooks) throw new Error('must use individualHooks'); },
beforeBulkUpdate: function(options){ if(!options.individualHooks) throw new Error('must use individualHooks'); },
beforeBulkDestroy: function(options){ if(!options.individualHooks) throw new Error('must use individualHooks'); },
beforeCreate: function(record, options){ if(!options.transaction) throw new Error('must use transaction'); },
beforeUpdate: function(record, options){ if(!options.transaction) throw new Error('must use transaction'); },
beforeDestroy: function(record, options){ if(!options.transaction) throw new Error('must use transaction'); }
}
}
};
#!/usr/bin/env node
//INTERFACE TESTS
/**
Tests the interface to the Db. This should try to be as implementation agnostic as possible.
However, it exposes the transaction and query methods on sequelize, which ties the interface
pretty closely with sequelize.
*/
module.exports = function(db, testDir){
require('shelljs/global');
var resolve = require('path').resolve,
basename = require('path').basename,
rimraf = require('rimraf'),
expect = require('chai').expect,
testConfig = require(resolve(__dirname, 'test_config.js'));
return function(){
beforeEach(function(){
if(!test('-d', testDir)) mkdir(testDir);
cp(testConfig.fsConfig.fsDb, testDir);
cp('-R', testConfig.fsConfig.fsTestModelDir + '/*', resolve(testDir, 'model'));
db = require(resolve(testDir, basename(testConfig.fsConfig.fsDb)))(testConfig);
});
afterEach(function(done){
rimraf(testDir, done);
});
it('should not close before open', function(){
return expect(db.close()).to.eventually.be.rejected;
});
it('should open', function(){
return expect(db.open()).to.eventually.be.fulfilled.then(function(){
return expect(db.close()).to.eventually.be.fulfilled;
});
});
it('should not open after open', function(){
return expect(db.open()).to.eventually.be.fulfilled
.then(function(){ return expect(db.open()).to.eventually.be.rejected; })
.then(function(){ return expect(db.close()).to.eventually.be.fulfilled; });
});
it('should not close after close', function(){
return expect(db.open()).to.eventually.be.fulfilled
.then(function(){ return expect(db.close()).to.eventually.be.fulfilled; })
.then(function(){ return expect(db.close()).to.eventually.be.rejected; });
});
it('should only get model(s) after open', function(){
expect(db.get('testModel')).to.be.null;
expect(db.getAll()).to.be.instanceOf(Array).and.have.length(0);
return expect(db.open()).to.eventually.be.fulfilled.then(function(){
return expect(db.get('testModel')).to.not.be.null;
return expect(db.getAll()).to.be.instanceOf(Array).and.have.length.above(0);
})
.then(function(){ return expect(db.close()).to.eventually.be.fulfilled; });
});
it('should not get model after close', function(){
return expect(db.open()).to.eventually.be.fulfilled
.then(function(){ return expect(db.get('testModel')).to.not.be.null; })
.then(function(){ return expect(db.close()).to.eventually.be.fulfilled; })
.then(function(){ return expect(db.get('testModel')).to.be.null; });
});
it('should get transaction', function(){
return expect(db.open()).to.eventually.be.fulfilled
.then(function(){ return expect(db.transaction).to.not.be.null; })
.then(function(){ return expect(db.close()).to.eventually.be.fulfilled; });
});
it('should get raw query', function(){
return expect(db.open()).to.eventually.be.fulfilled
.then(function(){ return expect(db.query).to.not.be.null; })
.then(function(){ return expect(db.close()).to.eventually.be.fulfilled; });
});
it('should require the same instance', function(){
return expect(db).to.equal(require(resolve(testDir, basename(testConfig.fsConfig.fsDb)))(testConfig));
});
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment