From 1d24ced22e2202dd049511d4b4d8d2775489c53d Mon Sep 17 00:00:00 2001 From: Adam Buczynski Date: Sat, 11 Jun 2016 16:41:51 +1200 Subject: [PATCH] Set properties plugin for mongoose --- app/plugins/mongoose/set-properties.js | 99 ++++++++++++++++++++++++++ app/services/db.js | 1 + app/user/user.ctrl.js | 8 ++- 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 app/plugins/mongoose/set-properties.js diff --git a/app/plugins/mongoose/set-properties.js b/app/plugins/mongoose/set-properties.js new file mode 100644 index 0000000..0c5a415 --- /dev/null +++ b/app/plugins/mongoose/set-properties.js @@ -0,0 +1,99 @@ +/* jshint -W083 */ +'use strict'; + +/** + * Dependencies + */ +let onlyId = require('../../helpers/only-id'); + +/** + * Recursive handler of objects + */ +function setObject(obj, data, parentPath) { + + //Loop all the keys + for (let key in data) { + if (data.hasOwnProperty(key)) { + + //Determine path + let path = parentPath ? (parentPath + '.' + key) : key; + + //If the current value is undefined, we set the data to whatever is given + if (typeof obj[key] === 'undefined') { + obj[key] = data[key]; + } + + //If the value is an array, it requires further handling + else if (Array.isArray(obj[key])) { + + //First, we would expect the data to be an array as well + if (!Array.isArray(data[key])) { + throw new Error( + 'Path `' + path + '` in data is expected to be an array`' + ); + } + + //Simplify the objects + let current = onlyId(obj[key]); + let updated = onlyId(data[key]); + + //Find items not present in the current array + if (updated.some(x => current.indexOf(x) === -1)) { + obj[key] = data[key]; + } + + //Find items not present in the updated array + else if (current.some(x => updated.indexOf(x) === -1)) { + obj[key] = data[key]; + } + } + + //If it's a date, check if the same + else if (obj[key] instanceof Date && data[key] instanceof Date) { + if (obj[key].getTime() !== data[key].getTime()) { + obj[key] = data[key]; + } + } + + //If the value is an object, it requires further handling + else if (typeof obj[key] === 'object') { + + //First, we would expect the data to be an object as well + if (typeof data[key] !== 'object') { + throw new Error( + 'Path `' + path + '` in data is expected to be an object`' + ); + } + + //If either the current value or the new value are null, it's safe + //to simply set the replacement value. + if (obj[key] === null || data[key] === null) { + obj[key] = data[key]; + continue; + } + + //Recursive object check + setObject(obj[key], data[key], key); + } + + //Anything else, check if changed + else if (obj[key] !== data[key]) { + obj[key] = data[key]; + } + } + } +} + +/** + * Set properties helper which will set only properties that have changed + * Note that for arrays, it assume primitive values + */ +module.exports = function setProperties(schema) { + + /** + * Method for all schema's + */ + schema.methods.setProperties = function(data) { + setObject(this, data); + }; +}; diff --git a/app/services/db.js b/app/services/db.js index 1f95ddd..313fac9 100644 --- a/app/services/db.js +++ b/app/services/db.js @@ -14,6 +14,7 @@ let config = require('../config'); */ mongoose.Promise = require('bluebird'); mongoose.plugin(require('../plugins/mongoose/to-json-plugin')); +mongoose.plugin(require('../plugins/mongoose/set-properties')); /** * Settings diff --git a/app/user/user.ctrl.js b/app/user/user.ctrl.js index 3e297ff..4d614a3 100644 --- a/app/user/user.ctrl.js +++ b/app/user/user.ctrl.js @@ -70,8 +70,12 @@ module.exports = { */ update(req, res, next) { - //Get user data and check if email changed - let user = Object.assign(req.user, req.data); + //Get user and data + let user = req.me; + let data = User.parseData(req.data); + + //Set data and check if email changed + user.setProperties(data); let isEmailChanged = user.isModified('email'); //Save user