diff --git a/README.md b/README.md index c61e543..f04e0b2 100644 --- a/README.md +++ b/README.md @@ -78,9 +78,11 @@ whereas the options are listed here (with default value). /* By default sequelize-temporal persist only changes, and saves the previous state in the history table. The "full" option saves all transactions into the temporal database (i.e. this includes the latest state.) - This allows to only query the hostory table to get the full history of an entity. + This allows to only query the history table to get the full history of an entity. */ - full: false + full: false, + /* All fields will be saved to history. Add field names to exclude from history. */ + excludeFields: [], ``` Details diff --git a/index.js b/index.js index a0dbfe6..3e46186 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,8 @@ var temporalDefaultOptions = { // runs the insert within the sequelize hook chain, disable // for increased performance blocking: true, - full: false + full: false, + excludeFields: [], }; var excludeAttributes = function(obj, attrsToExclude){ @@ -36,17 +37,27 @@ var Temporal = function(model, sequelize, temporalOptions){ }; var excludedAttributes = ["Model","unique","primaryKey","autoIncrement", "set", "get", "_modelAttribute"]; - var historyAttributes = _(model.rawAttributes).mapValues(function(v){ - v = excludeAttributes(v, excludedAttributes); - // remove the "NOW" defaultValue for the default timestamps - // we want to save them, but just a copy from our master record - if(v.fieldName == "createdAt" || v.fieldName == "updatedAt"){ - v.type = Sequelize.DATE; - } - return v; - }).assign(historyOwnAttrs).value(); - // If the order matters, use this: - //historyAttributes = _.assign({}, historyOwnAttrs, historyAttributes); + + var historyAttributes = _.reduce(_.keys(model.rawAttributes), function(acc, key) { + var v = excludeAttributes(model.rawAttributes[key], excludedAttributes); + // drop excluded fields + if ( + temporalOptions.excludeFields.length && + temporalOptions.excludeFields.includes(v.fieldName) + ) { + return acc + } + + // remove the "NOW" defaultValue for the default timestamps + // we want to save them, but just a copy from our master record + if(v.fieldName == "createdAt" || v.fieldName == "updatedAt"){ + v.type = Sequelize.DATE; + } + + acc[key] = v + return acc + }, {}) + historyAttributes = _.assign({}, historyOwnAttrs, historyAttributes); var historyOwnOptions = { timestamps: false diff --git a/test/test.js b/test/test.js index 0a7bc5c..8ce3eab 100644 --- a/test/test.js +++ b/test/test.js @@ -35,6 +35,20 @@ describe('Read-only API', function(){ return sequelize.sync({ force: true }); } + function freshDBWithExcludedFields() { + sequelize = new Sequelize('', '', '', { + dialect: 'sqlite', + storage: __dirname + '/.test.sqlite' + }); + User = Temporal(sequelize.define('User', { + name: Sequelize.TEXT, + fieldToExclude: Sequelize.TEXT, + }, { paranoid: true }), sequelize, { excludeFields: ['fieldToExclude'] }); + UserHistory = sequelize.models.UserHistory; + + return sequelize.sync({ force: true }); + } + function assertCount(modelHistory, n, opts){ // wrapped, chainable promise return function(obj){ @@ -332,4 +346,26 @@ describe('Read-only API', function(){ }); + describe('exclude fields option', function() { + + beforeEach(freshDBWithExcludedFields); + + it('onUpdate/onDestroy: shouldn\'t store excluded fields' , function(){ + return User.create() + .then(assertCount(UserHistory,0)) + .then(function(user){ + user.name = "foo"; + return user.save(); + }) + .then(function() { + return UserHistory.findAll(); + }) + .then(function(histories) { + assertCount(UserHistory, 1)(histories) + assert.equal(histories[0].fieldToExclude, null, 'fieldToExclude null') + }) + }); + + }) + });