UNPKG

sequelize-version

Version:

Automatically version (audit, log) your sequelize models

232 lines (185 loc) 6.8 kB
'use strict'; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var Sequelize = require('sequelize'); function capitalize(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function toArray(value) { return Array.isArray(value) ? value : [value]; } function clone(value) { return JSON.parse(JSON.stringify(value)); } function cloneAttrs(model, attrs, excludeAttrs) { var clone = {}; var attributes = model.rawAttributes || model.attributes; for (var p in attributes) { if (excludeAttrs.indexOf(p) > -1) continue; var nestedClone = {}; var attribute = attributes[p]; for (var np in attribute) { if (attrs.indexOf(np) > -1) { nestedClone[np] = attribute[np]; } } clone[p] = nestedClone; } return clone; } var VersionType = { CREATED: 1, UPDATED: 2, DELETED: 3 }; var Hook = { AFTER_CREATE: 'afterCreate', AFTER_UPDATE: 'afterUpdate', AFTER_DESTROY: 'afterDestroy', AFTER_SAVE: 'afterSave', AFTER_BULK_CREATE: 'afterBulkCreate' }; var defaults = { prefix: 'version', attributePrefix: '', suffix: '', schema: '', namespace: null, sequelize: null, exclude: [], tableUnderscored: true, underscored: true, versionAttributes: null }; function isEmpty(string) { return [undefined, null, NaN, ''].indexOf(string) > -1; } var hooks = [Hook.AFTER_CREATE, Hook.AFTER_UPDATE, Hook.AFTER_BULK_CREATE, Hook.AFTER_DESTROY]; var attrsToClone = ['type', 'field', 'get', 'set']; function getVersionType(hook) { switch (hook) { case Hook.AFTER_CREATE: case Hook.AFTER_BULK_CREATE: return VersionType.CREATED; case Hook.AFTER_UPDATE: return VersionType.UPDATED; case Hook.AFTER_DESTROY: return VersionType.DELETED; } throw new Error('Version type not found for hook ' + hook); } function Version(model, customOptions) { var _versionAttrs; var options = Object.assign({}, defaults, Version.defaults, customOptions); var prefix = options.prefix, suffix = options.suffix, namespace = options.namespace, exclude = options.exclude, tableUnderscored = options.tableUnderscored, underscored = options.underscored; if (isEmpty(prefix) && isEmpty(suffix)) { throw new Error('Prefix or suffix must be informed in options.'); } var sequelize = options.sequelize || model.sequelize; var schema = options.schema || model.options.schema; var attributePrefix = options.attributePrefix || options.prefix; var tableName = '' + (prefix ? '' + prefix + (tableUnderscored ? '_' : '') : '') + (model.options.tableName || model.name) + (suffix ? '' + (tableUnderscored ? '_' : '') + suffix : ''); var versionFieldType = '' + attributePrefix + (underscored ? '_t' : 'T') + 'ype'; var versionFieldId = '' + attributePrefix + (underscored ? '_i' : 'I') + 'd'; var versionFieldTimestamp = '' + attributePrefix + (underscored ? '_t' : 'T') + 'imestamp'; var versionModelName = '' + capitalize(prefix) + capitalize(model.name); var versionAttrs = (_versionAttrs = {}, _defineProperty(_versionAttrs, versionFieldId, { type: Sequelize.BIGINT, primaryKey: true, autoIncrement: true }), _defineProperty(_versionAttrs, versionFieldType, { type: Sequelize.INTEGER, allowNull: false }), _defineProperty(_versionAttrs, versionFieldTimestamp, { type: Sequelize.DATE, allowNull: false }), _versionAttrs); var cloneModelAttrs = cloneAttrs(model, attrsToClone, exclude); var versionModelAttrs = Object.assign({}, cloneModelAttrs, versionAttrs); var versionModelOptions = { schema: schema, tableName: tableName, timestamps: false }; var versionModel = sequelize.define(versionModelName, versionModelAttrs, versionModelOptions); hooks.forEach(function (hook) { model.addHook(hook, function (instanceData, _ref) { var transaction = _ref.transaction; var cls = namespace || Sequelize.cls; var versionTransaction = void 0; if (sequelize === model.sequelize) { versionTransaction = cls ? cls.get('transaction') || transaction : transaction; } else { versionTransaction = cls ? cls.get('transaction') : undefined; } var versionType = getVersionType(hook); var instancesData = toArray(instanceData); var versionData = instancesData.map(function (data) { var _Object$assign; return Object.assign({}, clone(data), (_Object$assign = {}, _defineProperty(_Object$assign, versionFieldType, versionType), _defineProperty(_Object$assign, versionFieldTimestamp, new Date()), _Object$assign)); }); return versionModel.bulkCreate(versionData, { transaction: versionTransaction }); }); }); versionModel.addScope('created', { where: _defineProperty({}, versionFieldType, VersionType.CREATED) }); versionModel.addScope('updated', { where: _defineProperty({}, versionFieldType, VersionType.UPDATED) }); versionModel.addScope('deleted', { where: _defineProperty({}, versionFieldType, VersionType.DELETED) }); function getVersions(params) { var _this = this; var versionParams = {}; var modelAttributes = model.rawAttributes || model.attributes; var primaryKeys = Object.keys(modelAttributes).filter(function (attr) { return modelAttributes[attr].primaryKey; }); if (primaryKeys.length) { versionParams.where = primaryKeys.map(function (attr) { return _defineProperty({}, attr, _this[attr]); }).reduce(function (a, b) { return Object.assign({}, a, b); }); } if (params) { if (params.where) versionParams.where = Object.assign({}, params.where, versionParams.where); versionParams = Object.assign({}, params, versionParams); } return versionModel.findAll(versionParams); } // Sequelize V4 and above if (model.prototype) { if (!model.prototype.hasOwnProperty('getVersions')) { model.prototype.getVersions = getVersions; } //Sequelize V3 and below } else { var hooksForBind = hooks.concat([Hook.AFTER_SAVE]); hooksForBind.forEach(function (hook) { model.addHook(hook, function (instance) { var instances = toArray(instance); instances.forEach(function (i) { if (!i.getVersions) i.getVersions = getVersions; }); }); }); } if (!model.getVersions) { model.getVersions = function (params) { return versionModel.findAll(params); }; } return versionModel; } Version.defaults = Object.assign({}, defaults); Version.VersionType = VersionType; module.exports = Version;