UNPKG

chrobject

Version:

Stores chronicles of plain objects as diffs and snapshots

239 lines (238 loc) 10.6 kB
/** * Creator: Christian Hotz * Company: hydra newmedia GmbH * Date: 11.06.16 * * Copyright hydra newmedia GmbH */ "use strict"; /** * Imports */ var _ = require('lodash'); var hash = require('object-hash'); var Snapshot_1 = require('../utils/Snapshot'); var Diff_1 = require('../utils/Diff'); var DeepDiff_1 = require('../utils/DeepDiff'); var EntryAppService = (function () { function EntryAppService(entity, storage, options) { this.entity = entity; this.storage = storage; this.options = { ignoreProperties: [], ignoreSubProperties: [] }; if (options) { this.options.ignoreProperties = options.ignoreProperties || []; this.options.ignoreSubProperties = options.ignoreSubProperties || []; } } EntryAppService.prototype.getDiffs = function (condition, callback) { if (!condition) { condition = {}; } this.storage.findDiffsByCondition(condition, this.entity, callback); }; EntryAppService.prototype.getSnapshotById = function (id, callback) { this.storage.findSnapshotById(id, this.entity, callback); }; EntryAppService.prototype.saveSnapshotAndDiff = function (obj, creator, timestamp, callback) { var _this = this; var id = _.get(obj, this.entity.idPath); this.storage.findLatestSnapshotBefore(id, timestamp, this.entity, function (err, oldSnap) { if (err) { return callback(err); } var newSnap = new Snapshot_1.Snapshot(obj, _this.entity, creator, timestamp); var diff; if (oldSnap) { diff = _this.diff(oldSnap, newSnap); } else { var blankSnap = new Snapshot_1.Snapshot({}, _this.entity, creator, timestamp); diff = _this.diff(blankSnap.setObjId(newSnap.objId), newSnap); } if (!diff.isEmpty()) { _this.storage.insertSnapshot(newSnap, function (err, newSnap) { if (err) { return callback(err); } diff.linkToId(newSnap.id); _this.storage.insertDiff(diff, function (err, diff) { if (callback) { callback(err, { snapshot: newSnap, diff: diff }); } }); }); } else { callback(null, { snapshot: null, diff: null }); } }); }; EntryAppService.prototype.saveSnapshot = function (obj, creator, timestamp, callback) { var _this = this; var id = _.get(obj, this.entity.idPath); this.storage.findLatestSnapshotBefore(id, timestamp, this.entity, function (err, oldSnap) { if (err) { return callback(err); } var newSnap = new Snapshot_1.Snapshot(obj, _this.entity, creator, timestamp); var diff; if (oldSnap) { diff = _this.diff(oldSnap, newSnap); } else { var blankSnap = new Snapshot_1.Snapshot({}, _this.entity, creator, timestamp); diff = _this.diff(blankSnap.setObjId(newSnap.objId), newSnap); } if (!diff.isEmpty()) { _this.storage.insertSnapshot(newSnap, callback); } else { callback(null, null); } }); }; EntryAppService.prototype.saveDiff = function (obj, creator, timestamp, callback) { var _this = this; var id = _.get(obj, this.entity.idPath); this.storage.findLatestSnapshotBefore(id, timestamp, this.entity, function (err, oldSnap) { if (err) { return callback(err); } var newSnap = new Snapshot_1.Snapshot(obj, _this.entity, creator, timestamp, oldSnap ? oldSnap.id : undefined); var diff; if (oldSnap) { diff = _this.diff(oldSnap, newSnap); } else { var blankSnap = new Snapshot_1.Snapshot({}, _this.entity, creator, timestamp); diff = _this.diff(blankSnap.setObjId(newSnap.objId), newSnap); } if (!diff.isEmpty()) { _this.storage.upsertSnapshot(newSnap, function (err, newSnap) { if (err) { return callback(err); } else { _this.storage.insertDiff(diff, callback ? callback : undefined); } }); } else { callback(null, null); } }); }; EntryAppService.prototype.diff = function (snapOne, snapTwo) { // Check if snapshots are of same object if (snapOne.objId !== snapTwo.objId) { throw new Error('Diffed snapshots are not of same object'); } // Check if snapshots are of same entity if (!snapOne.entity.equals(snapTwo.entity)) { throw new Error('Diffed snapshots are not of same entity'); } // swap snapshots if snapTwo was taken before snapOne if (snapOne.timestamp > snapTwo.timestamp) { var tmp = snapOne; snapOne = snapTwo; snapTwo = tmp; } // diff between the two snapshots var diffObj = this.deepDiff(snapOne.obj, snapTwo.obj); return new Diff_1.Diff(diffObj, snapTwo.objId, snapTwo.entity, snapTwo.creator, snapTwo.timestamp); }; EntryAppService.prototype.deepDiff = function (one, two, path) { var _this = this; if (path === void 0) { path = ''; } var result = []; var unsetIgnoredSubProperties = function (obj) { if (_.isPlainObject(obj)) { for (var _i = 0, _a = _this.options.ignoreSubProperties; _i < _a.length; _i++) { var prop = _a[_i]; _.unset(obj, prop); } } }; _.keys(one).forEach(function (key) { var concatPath = path ? path + '.' + key : key; if (!_.includes(_this.options.ignoreProperties, concatPath) && !_.includes(_this.options.ignoreSubProperties, concatPath)) { unsetIgnoredSubProperties(one[key]); unsetIgnoredSubProperties(two[key]); var getDeletedProperties_1 = function (obj, propPath) { if (propPath === void 0) { propPath = null; } if (_.isPlainObject(obj)) { for (var _i = 0, _a = _.keys(obj); _i < _a.length; _i++) { var objKey = _a[_i]; unsetIgnoredSubProperties(obj[objKey]); getDeletedProperties_1(obj[objKey], propPath ? propPath + '.' + objKey : objKey); } } else if (_.isBoolean(obj) || _.isDate(obj) || _.isNumber(obj) || _.isNull(obj) || _.isRegExp(obj) || _.isString(obj) || _.isArray(obj)) { result.push(new DeepDiff_1.DeepDiff('deleted', propPath, obj, null)); } }; if (_.isPlainObject(one[key])) { if (!_.has(two, key)) { getDeletedProperties_1(one[key], concatPath); } else { result = _.concat(result, _this.deepDiff(one[key], two[key], path ? path + '.' + key : key)); } } else if (_.isBoolean(one[key]) || _.isDate(one[key]) || _.isNumber(one[key]) || _.isNull(one[key]) || _.isRegExp(one[key]) || _.isString(one[key])) { if (!_.has(two, key)) { result.push(new DeepDiff_1.DeepDiff('deleted', concatPath, one[key], null)); } else if (_.isDate(one[key]) || _.isDate(two[key])) { if (new Date(one[key]).valueOf() !== new Date(two[key]).valueOf()) { result.push(new DeepDiff_1.DeepDiff('edited', concatPath, new Date(one[key]), new Date(two[key]))); } } else if (hash(one[key]) !== hash(two[key])) { result.push(new DeepDiff_1.DeepDiff('edited', concatPath, one[key], two[key])); } } else if (_.isArray(one[key]) && _.isArray(two[key]) && !_.isEqual(one[key], two[key])) { for (var i = 0; i < one[key].length; i++) { unsetIgnoredSubProperties(one[key][i]); } for (var i = 0; i < two[key].length; i++) { unsetIgnoredSubProperties(two[key][i]); } if (hash(one[key]) !== hash(two[key])) { result.push(new DeepDiff_1.DeepDiff('array', concatPath, one[key], two[key])); } } else if (!_.has(two, key)) { getDeletedProperties_1(one[key], concatPath); } } }); var getCreatedProperties = function (obj, path) { if (path === void 0) { path = null; } for (var _i = 0, _a = _.keys(path ? _.get(obj, path) : obj); _i < _a.length; _i++) { var key = _a[_i]; var concatPath = path ? path + '.' + key : key; var val = _.get(two, concatPath); unsetIgnoredSubProperties(val); if (!_.includes(_this.options.ignoreProperties, concatPath)) { if (_.isBoolean(val) || _.isDate(val) || _.isNumber(val) || _.isNull(val) || _.isRegExp(val) || _.isString(val) || _.isArray(val)) { if (!_.has(one, concatPath)) { result.push(new DeepDiff_1.DeepDiff('created', concatPath, null, val)); } } else if (_.isPlainObject(val)) { getCreatedProperties(obj, concatPath); } } } }; getCreatedProperties(two, path); return result; }; return EntryAppService; }()); exports.EntryAppService = EntryAppService;