BE-SPAN/node_modules/sequelize-oracle/lib/plugins/counter-cache.js
githubna-ilham 722cd440e8 first commit
2024-10-20 22:04:16 +07:00

178 lines
5.2 KiB
JavaScript

'use strict';
var Utils = require('./../utils')
, Helpers = require('../associations/helpers')
, DataTypes = require('../data-types')
, Promise = require('bluebird');
var CounterCache = function(association, options) {
this.association = association;
this.source = association.source;
this.target = association.target;
this.options = options || {};
this.sequelize = this.source.modelManager.sequelize;
this.as = this.options.as;
if (association.associationType !== 'HasMany') {
throw new Error('Can only have CounterCache on HasMany association');
}
if (this.as) {
this.isAliased = true;
this.columnName = this.as;
} else {
this.as = 'count_' + this.target.options.name.plural;
this.columnName = Utils._.camelizeIf(
this.as,
!this.source.options.underscored
);
}
this.injectAttributes();
this.injectHooks();
};
// Add countAssociation attribute to source model
CounterCache.prototype.injectAttributes = function() {
// Do not try to use a column that's already taken
Helpers.checkNamingCollision(this);
var newAttributes = {};
newAttributes[this.columnName] = {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: Utils._.partial(
Utils.toDefaultValue,
0
)
};
Utils.mergeDefaults(this.source.rawAttributes, newAttributes);
// Sync attributes and setters/getters to DAO prototype
this.source.refreshAttributes();
};
// Add setAssociaton method to the prototype of the model instance
CounterCache.prototype.injectHooks = function() {
var association = this.association,
counterCacheInstance = this,
CounterUtil,
fullUpdateHook,
atomicHooks,
previousTargetId;
CounterUtil = {
update: function (targetId, options) {
var query = CounterUtil._targetQuery(targetId);
return association.target.count({ where: query, logging: options && options.logging }).then(function (count) {
var newValues = {};
query = CounterUtil._sourceQuery(targetId);
newValues[counterCacheInstance.columnName] = count;
return association.source.update(newValues, { where: query, logging: options && options.logging });
});
},
increment: function (targetId, options) {
var query = CounterUtil._sourceQuery(targetId);
return association.source.find({ where: query, logging: options && options.logging }).then(function (instance) {
return instance.increment(counterCacheInstance.columnName, { by: 1, logging: options && options.logging });
});
},
decrement: function (targetId, options) {
var query = CounterUtil._sourceQuery(targetId);
return association.source.find({ where: query, logging: options && options.logging }).then(function (instance) {
return instance.decrement(counterCacheInstance.columnName, { by: 1, logging: options && options.logging });
});
},
// helpers
_targetQuery: function (id) {
var query = {};
query[association.identifier] = id;
return query;
},
_sourceQuery: function (id) {
var query = {};
query[association.source.primaryKeyAttribute] = id;
return query;
}
};
fullUpdateHook = function (target, options) {
var targetId = target.get(association.identifier)
, promises = [];
if (targetId) {
promises.push(CounterUtil.update(targetId, options));
}
if (previousTargetId && previousTargetId !== targetId) {
promises.push(CounterUtil.update(previousTargetId, options));
}
return Promise.all(promises).return(undefined);
};
atomicHooks = {
create: function (target, options) {
var targetId = target.get(association.identifier);
if (targetId) {
return CounterUtil.increment(targetId, options);
}
},
update: function (target, options) {
var targetId = target.get(association.identifier)
, promises = [];
if (targetId && !previousTargetId) {
promises.push(CounterUtil.increment(targetId, options));
}
if (!targetId && previousTargetId) {
promises.push(CounterUtil.decrement(targetId, options));
}
if (previousTargetId && targetId && previousTargetId !== targetId) {
promises.push(CounterUtil.increment(targetId, options));
promises.push(CounterUtil.decrement(previousTargetId, options));
}
return Promise.all(promises);
},
destroy: function (target, options) {
var targetId = target.get(association.identifier);
if (targetId) {
return CounterUtil.decrement(targetId, options);
}
}
};
// previousDataValues are cleared before afterUpdate, so we need to save this here
association.target.addHook('beforeUpdate', function (target) {
previousTargetId = target.previous(association.identifier);
});
if (this.options.atomic === false) {
association.target.addHook('afterCreate', fullUpdateHook);
association.target.addHook('afterUpdate', fullUpdateHook);
association.target.addHook('afterDestroy', fullUpdateHook);
} else {
association.target.addHook('afterCreate', atomicHooks.create);
association.target.addHook('afterUpdate', atomicHooks.update);
association.target.addHook('afterDestroy', atomicHooks.destroy);
}
};
module.exports = CounterCache;