diff --git a/lib/SequelizeResolver.ts b/lib/SequelizeResolver.ts index 0e338fd..a8374c9 100644 --- a/lib/SequelizeResolver.ts +++ b/lib/SequelizeResolver.ts @@ -8,6 +8,7 @@ export class SequelizeResolver extends FabrixResolver { private _schema private _sequelize private _sequelizeModel + private _plugins constructor (model: FabrixModel, datastore?: Sequelize) { super(model) @@ -37,6 +38,10 @@ export class SequelizeResolver extends FabrixResolver { return this._sequelize } + get plugins() { + return this._sequelize ? this._sequelize.plugins : new Set() + } + /** * Get options provided to the model when connected */ diff --git a/lib/SequelizeSpool.ts b/lib/SequelizeSpool.ts index bb97ab6..b75fa62 100755 --- a/lib/SequelizeSpool.ts +++ b/lib/SequelizeSpool.ts @@ -72,7 +72,7 @@ export class SequelizeSpool extends DatastoreSpool { */ configure() { // This set tracks the plugins that are being added to a single sequelize instance - this._datastore['plugins'] = this._datastore['plugins'] || new Set() + this._datastore['plugins'] = this._datastore['plugins'] || new Map([['plugins', new Set()]]) this._plugins = Transformer.getPlugins(this.app) // Holds a collection of the connections made through Sequelize diff --git a/lib/transformer.ts b/lib/transformer.ts index 84c03cf..7c3205d 100755 --- a/lib/transformer.ts +++ b/lib/transformer.ts @@ -202,18 +202,15 @@ export const Transformer = { definePlugins(app: FabrixApp, store_config = {}, plugins = {}) { const global_plugins = Object.keys(plugins) - const store_plugins = Object.keys(store_config).filter(n => { - if (global_plugins.indexOf(n) === -1) { - return n - } - }) + const store_plugins = Object.keys(store_config) const plugs = new Map() global_plugins.forEach(n => { plugs.set(n, plugins[n]) }) + store_plugins.forEach(n => { - plugs.set(n, plugins[n]) + plugs.set(n, store_config[n]) }) return plugs @@ -221,10 +218,14 @@ export const Transformer = { /** * Create Sequelize object based on config options - * @param {Object} app.config.store + * @param {FabrixApp} app + * @param {Sequelize} sequelize + * @param {String} name + * @param {Object} config from config.stores + * @param {Object} plugins global plugins from config.sequelize * @return {Sequelize} Sequelize instance */ - createConnectionsFromConfig (app: FabrixApp, sequelize, config: {[key: string]: any}, plugins: {[key: string]: any} = {}) { + createConnectionsFromConfig (app: FabrixApp, sequelize, name, config: {[key: string]: any}, plugins: {[key: string]: any} = {}) { const logger = function(val) { // https://github.com/sequelize/sequelize/issues/3781#issuecomment-421282703 // If for whatever reason the Sequelize logger exports a Sequelize object, then, this must be done @@ -236,11 +237,22 @@ export const Transformer = { const plugs: Map = Transformer.definePlugins(app, config.plugins, plugins) + // Resolve or Define Connection plugin namespace + if (!sequelize.plugins.has(name)) { + sequelize.plugins.set(name, new Set()) + } + // Make a copy so plugins don't collide on multiple stores let Seq = sequelize + // Quick check to see if sequelize is already started + if (Seq instanceof sequelize) { + throw new Error('Sequelize is already initialized and cannot be loaded again, check your plugins') + } + + // For each of the defined plugs plugs.forEach((plug, key, map) => { - if (!sequelize.plugins.has(key)) { + if (!sequelize.plugins.get('plugins').has(key) && !sequelize.plugins.get(name).has(key)) { try { if (typeof plug === 'function') { Seq = plug(Seq) @@ -251,10 +263,12 @@ export const Transformer = { else { app.log.debug(`Transformer: ${key} ${plug} was not a function or Fabrix sequelize object`) } - sequelize.plugins.add(key) + sequelize.plugins.get('plugins').add(key) + sequelize.plugins.get(name).add(key) } catch (err) { - app.log.error(err) + console.log('BRK err', err) + app.log.error(`${key} plugin threw an error:`, err) } } else { @@ -262,41 +276,34 @@ export const Transformer = { } }) - // // Add plugins - // plugs.forEach((plug: any) => { - // try { - // if (typeof plug === 'function') { - // Seq = plug(Seq) - // } - // else if (typeof plug === 'object' && plug.func && plug.config) { - // Seq = plug.func(Seq, plug.config) - // } - // else { - // app.log.debug(`Transformer: ${plug} was not a function or Fabrix sequelize object`) - // } - // } - // catch (err) { - // app.log.error(err) - // } - // }) + // Log out that the plugins were added + app.log.silly(`${ Array.from(sequelize.plugins.get(name))} installed on connection`) + // Based on the config, initialize the sequelize instance if (config.uri) { // Sequelize modify options object - return new Seq(config.uri, Object.assign({}, { logging: logger }, config)) + Seq = new Seq(config.uri, Object.assign({}, { logging: logger }, config)) } else { - return new Seq( + Seq = new Seq( config.database, config.username || process.env.POSTGRES_USER, config.password || process.env.POSTGRES_PASSWORD, + // Sequelize modify options object Object.assign({}, { logging: logger }, config) ) } + + // A handy way to see what plugins are loaded on the connection instance added to the resolver + Seq.plugins = sequelize.plugins.get(name) + + return Seq }, /** * Pick only Sequelize SQL stores from app config */ + // TODO, this is too greedy, it should likely just grab stores that define the orm.sequelize pickStores (stores): {[key: string]: any} { return pickBy(stores, (_store, name) => { return ((_store.dialect && isString(_store.dialect) && _store.orm === 'sequelize') @@ -326,7 +333,7 @@ export const Transformer = { const stores = Transformer.pickStores(app.config.get('stores')) const _sequelize = {} Object.keys(stores).forEach(key => { - _sequelize[key] = Transformer.createConnectionsFromConfig(app, sequelize, stores[key], plugins) + _sequelize[key] = Transformer.createConnectionsFromConfig(app, sequelize, key, stores[key], plugins) _sequelize[key].fabrixApp = app _sequelize[key].migrate = stores[key].migrate _sequelize[key].models = {} diff --git a/package-lock.json b/package-lock.json index 4144c31..fa7a894 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@fabrix/spool-sequelize", - "version": "1.6.15", + "version": "1.6.16", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 13cd885..6ee9c0c 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fabrix/spool-sequelize", - "version": "1.6.15", + "version": "1.6.16", "description": "Spool - Datastore Spool for Sequelize.js http://sequelizejs.com", "scripts": { "build": "tsc -p ./lib/tsconfig.release.json", diff --git a/test/fixtures/testPlugin2.js b/test/fixtures/testPlugin2.js index 6498acb..bce020b 100644 --- a/test/fixtures/testPlugin2.js +++ b/test/fixtures/testPlugin2.js @@ -2,5 +2,13 @@ module.exports = function(Sequelize, config) { if (!Sequelize) { Sequelize = require('sequelize') } + + if (Sequelize.prototype.helloEarth) { + throw new Error('PLUGIN WAS DOUBLED LOADED') + } + Sequelize.prototype.helloEarth = function() { + return 'hello earth' + } + return Sequelize } diff --git a/test/integrations/spool.test.js b/test/integrations/spool.test.js index f24a456..c068bf8 100755 --- a/test/integrations/spool.test.js +++ b/test/integrations/spool.test.js @@ -22,13 +22,36 @@ describe('Spool', () => { }) }) - it('should be able to access the datastore service', (done) => { + it('should be able to access the datastore service on model 1', (done) => { assert(global.app.models.testModel.resolver.datastore) assert(global.app.models.testModel.resolver.sequelize) assert(global.app.models.testModel.datastore) assert(global.app.models.testModel.sequelize) assert.equal(global.app.models.testModel.sequelize, global.app.models.testModel.resolver.sequelize) assert.equal(global.app.models.testModel.instance, global.app.models.testModel.resolver.sequelizeModel) + assert(global.app.models.testModel.resolver.plugins) + done() + }) + + it('should be able to access the datastore service on model 2', (done) => { + assert(global.app.models.testModel2.resolver.datastore) + assert(global.app.models.testModel2.resolver.sequelize) + assert(global.app.models.testModel2.datastore) + assert(global.app.models.testModel2.sequelize) + assert.equal(global.app.models.testModel2.sequelize, global.app.models.testModel2.resolver.sequelize) + assert.equal(global.app.models.testModel2.instance, global.app.models.testModel2.resolver.sequelizeModel) + assert(global.app.models.testModel2.resolver.plugins) + done() + }) + + it('should be able to access the datastore service on model 3', (done) => { + assert(global.app.models.testModel3.resolver.datastore) + assert(global.app.models.testModel3.resolver.sequelize) + assert(global.app.models.testModel3.datastore) + assert(global.app.models.testModel3.sequelize) + assert.equal(global.app.models.testModel3.sequelize, global.app.models.testModel3.resolver.sequelize) + assert.equal(global.app.models.testModel3.instance, global.app.models.testModel3.resolver.sequelizeModel) + assert(global.app.models.testModel3.resolver.plugins) done() }) diff --git a/test/unit/lib/SequelizeResolver.test.js b/test/unit/lib/SequelizeResolver.test.js new file mode 100644 index 0000000..e69de29 diff --git a/test/unit/lib/transformer.test.js b/test/unit/lib/transformer.test.js index ba135a4..5efd9b3 100755 --- a/test/unit/lib/transformer.test.js +++ b/test/unit/lib/transformer.test.js @@ -15,8 +15,10 @@ describe('lib.Transformer', () => { const plugins = lib.Transformer.getPlugins(app) const connections = lib.Transformer.getConnections(app, Sequelize, plugins) const models = lib.Transformer.getModels(app, Sequelize, connections) + assert.ok(plugins) assert.equal(Sequelize.prototype.helloWorld(), 'hello world') + assert.equal(Sequelize.prototype.helloEarth(), 'hello earth') }) })