From efe2f7c167e300111067c3bd9a09bd5888fe40f3 Mon Sep 17 00:00:00 2001 From: Russ Nicoletti Date: Fri, 20 Jan 2017 15:58:25 -0800 Subject: [PATCH] [Issue #228] consumers to add model hooks --- example/example.js | 11 +++++- src/models/db.js | 22 ++++++++++++ test/server.js | 56 +++++++++++++++++++++++++++-- test/test_client_db_hooks.js | 70 ++++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 test/test_client_db_hooks.js diff --git a/example/example.js b/example/example.js index c185353..aef76c8 100644 --- a/example/example.js +++ b/example/example.js @@ -13,7 +13,16 @@ const config = { port: 5432, name: 'sensorthingsexample', user: 'postgres', - password: '12345678' + password: '12345678', + hooks: { + 'beforeCreate': (instance, options) => { + if (instance.$modelOptions.name.plural === 'Things') { + instance.properties = Object.assign({}, instance.properties, { + MozillaSensorWebOwner: 'client-name' + }); + } + } + } } }; diff --git a/src/models/db.js b/src/models/db.js index 5cebab6..f8d1e8c 100644 --- a/src/models/db.js +++ b/src/models/db.js @@ -28,6 +28,19 @@ const IDLE = 0 const INITIALIZING = 1; const READY = 2; +const hooks = [ + 'beforeValidate', + 'afterValidate', + 'beforeCreate', + 'afterCreate', + 'beforeDestroy', + 'afterDestroy', + 'beforeRestore', + 'afterRestore', + 'beforeUpdate', + 'afterUpdate' +]; + const Deferred = function Deferred () { this.promise = new Promise((resolve, reject) => { this.resolve = resolve; @@ -82,6 +95,15 @@ export default config => { if ('associate' in db[modelName]) { db[modelName].associate(db); } + + if (!config.hooks) { + return; + } + + hooks.forEach(hook => { + const clientHook = config.hooks[hook]; + clientHook && db[modelName].hook(hook, clientHook); + }); }); db.sequelize = sequelize; diff --git a/test/server.js b/test/server.js index 7ad3375..457e20b 100644 --- a/test/server.js +++ b/test/server.js @@ -13,9 +13,61 @@ const config = { port: 5432, name: 'sensorthingstest', user: 'postgres', - pass: '12345678' + pass: '12345678', + hooks: { + 'beforeValidate': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + beforeValidate: 'beforeValidate' + }); + }, + 'afterValidate': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + afterValidate: 'afterValidate' + }); + }, + 'beforeCreate': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + beforeCreate: 'beforeCreate' + }); + }, + 'afterCreate': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + afterCreate: 'afterCreate' + }); + }, + 'beforeDestroy': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + beforeDestroy: 'beforeDestroy' + }); + }, + 'afterDestroy': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + afterDestroy: 'afterDestroy' + }); + }, + 'beforeRestore': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + beforeRestore: 'beforeRestore' + }); + }, + 'afterRestore': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + afterRestore: 'afterRestore' + }); + }, + 'beforeUpdate': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + beforeUpdate: 'beforeUpdate' + }); + }, + 'afterUpdate': (instance, options) => { + instance.properties = Object.assign({}, instance.properties, { + afterUpdate: 'afterUpdate' + }); + } + } } -}; +} app.use('/', SensorThings(config)); diff --git a/test/test_client_db_hooks.js b/test/test_client_db_hooks.js new file mode 100644 index 0000000..e7bd60a --- /dev/null +++ b/test/test_client_db_hooks.js @@ -0,0 +1,70 @@ +import app from './server'; +import db from '../src/models/db'; +import { + datastreams, + DatastreamsEntity, + entities, + featuresOfInterest, + FeaturesOfInterestEntity, + historicalLocations, + HistoricalLocationsEntity, + locations, + LocationsEntity, + observations, + ObservationsEntity, + observedProperties, + ObservedPropertiesEntity, + sensors, + SensorsEntity, + things, + ThingsEntity +} from './constants'; +import supertest from 'supertest'; + +const server = supertest.agent(app.listen(8890)); + +db().then(models => { + describe('db hooks', () => { + beforeEach(done => { + models.sequelize.transaction(transaction => { + return Promise.all(Object.keys(entities).map(name => { + return models[name].destroy({ transaction, where: {} }); + })); + }).then(() => done()); + }); + + [ + [ datastreams, DatastreamsEntity ], + [ featuresOfInterest, FeaturesOfInterestEntity ], + [ historicalLocations, HistoricalLocationsEntity ], + [ locations, LocationsEntity ], + [ observations, ObservationsEntity ], + [ observedProperties, ObservedPropertiesEntity ], + [ sensors, SensorsEntity ], + [ things, ThingsEntity ] + ].forEach(testObj => { + it(testObj[0] + ' db \"create\" hooks', done => { + models[testObj[0]].create(testObj[1]).then(instance => { + const expectedMap = new Map(); + [ + ['beforeValidate', 'beforeValidate'], + ['afterValidate', 'afterValidate'], + ['beforeCreate', 'beforeCreate'], + ['afterCreate', 'afterCreate'] + ].map(expectedObj => { + expectedMap.set(expectedObj[0], expectedObj[1]); + }); + const instanceProperties = Object.entries(instance.properties); + const propIndex = (instance.$modelOptions.name.plural === 'Things') ? 3 : 0; + for (var i = 0; i < instanceProperties.length; i++) { + const expectedHook = expectedMap.get(instanceProperties[i + propIndex][0]); + const instanceHook = instanceProperties[i + propIndex][1]; + expectedHook.should.be.equal(instanceHook); + } + }); + done(); + }) + }); + }); +}); +