Created
September 1, 2015 15:18
-
-
Save ssteffl/132afcdc7e1c296b7f51 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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; | |
} | |
}; | |
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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'); } | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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