不要怂,就是干,撸起袖子干!

Commit f5c56a8b by Jan Aagaard Meier

remove(plugin): Counter cache)

1 parent aace1250
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
- [FIXED] `hasOne` now prefer aliases to construct foreign key [#5247](https://github.com/sequelize/sequelize/issues/5247) - [FIXED] `hasOne` now prefer aliases to construct foreign key [#5247](https://github.com/sequelize/sequelize/issues/5247)
- [CHANGED] `instance.equals` now only checks primary keys, instead of all attributes. - [CHANGED] `instance.equals` now only checks primary keys, instead of all attributes.
- [REWRITE] Rewrite model and instance to a single class - instance instanceof Model [#5924](https://github.com/sequelize/sequelize/issues/5924) - [REWRITE] Rewrite model and instance to a single class - instance instanceof Model [#5924](https://github.com/sequelize/sequelize/issues/5924)
- [REMOVED] Counter cache plugin
## BC breaks: ## BC breaks:
- `hookValidate` removed in favor of `validate` with `hooks: true | false`. `validate` returns a promise which is rejected if validation fails - `hookValidate` removed in favor of `validate` with `hooks: true | false`. `validate` returns a promise which is rejected if validation fails
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
- `hasOne` now prefer `as` option to generate foreign key name, otherwise it defaults to source model name - `hasOne` now prefer `as` option to generate foreign key name, otherwise it defaults to source model name
- `instance.equals` now provides reference equality (do two instances refer to the same row, i.e. are their primary key(s) equal). Use `instance.get()` to get and compare all values. - `instance.equals` now provides reference equality (do two instances refer to the same row, i.e. are their primary key(s) equal). Use `instance.get()` to get and compare all values.
- Instances (database rows) are now instances of the model, instead of being a separate class. This means you can replace User.build() with new User() and sequelize.define with User extends Sequelize.Model. See #5924 - Instances (database rows) are now instances of the model, instead of being a separate class. This means you can replace User.build() with new User() and sequelize.define with User extends Sequelize.Model. See #5924
- The counter cache plugin, and consequently the `counterCache` option for associations has been removed. The plugin is seeking a new maintainer - You can find the code [here](https://github.com/sequelize/sequelize/blob/aace1250dfa8cd81a4edfd2086c9058b513f6ee0/lib/plugins/counter-cache.js)
# 3.23.2 # 3.23.2
- [FIXED] Type validation now works with non-strings due to updated validator@5.0.0 [#5861](https://github.com/sequelize/sequelize/pull/5861) - [FIXED] Type validation now works with non-strings due to updated validator@5.0.0 [#5861](https://github.com/sequelize/sequelize/pull/5861)
......
...@@ -7,7 +7,6 @@ var Utils = require('./../utils') ...@@ -7,7 +7,6 @@ var Utils = require('./../utils')
, BelongsTo = require('./belongs-to') , BelongsTo = require('./belongs-to')
, HasMany = require('./has-many') , HasMany = require('./has-many')
, HasOne = require('./has-one') , HasOne = require('./has-one')
, CounterCache = require('../plugins/counter-cache')
, util = require('util'); , util = require('util');
/** /**
...@@ -294,10 +293,6 @@ var BelongsToMany = function(source, target, options) { ...@@ -294,10 +293,6 @@ var BelongsToMany = function(source, target, options) {
*/ */
count: 'count' + plural count: 'count' + plural
}; };
if (this.options.counterCache) {
new CounterCache(this, this.options.counterCache !== true ? this.options.counterCache : {});
}
}; };
util.inherits(BelongsToMany, Association); util.inherits(BelongsToMany, Association);
......
...@@ -4,7 +4,6 @@ var Utils = require('./../utils') ...@@ -4,7 +4,6 @@ var Utils = require('./../utils')
, Helpers = require('./helpers') , Helpers = require('./helpers')
, _ = require('lodash') , _ = require('lodash')
, Association = require('./base') , Association = require('./base')
, CounterCache = require('../plugins/counter-cache')
, util = require('util'); , util = require('util');
/** /**
...@@ -188,11 +187,6 @@ var HasMany = function(source, target, options) { ...@@ -188,11 +187,6 @@ var HasMany = function(source, target, options) {
*/ */
count: 'count' + plural count: 'count' + plural
}; };
if (this.options.counterCache) {
new CounterCache(this, this.options.counterCache !== true ? this.options.counterCache : {});
delete this.accessors.count;
}
}; };
util.inherits(HasMany, Association); util.inherits(HasMany, Association);
......
'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.foreignKey] = id;
return query;
},
_sourceQuery: function (id) {
var query = {};
query[association.source.primaryKeyAttribute] = id;
return query;
}
};
fullUpdateHook = function (target, options) {
var targetId = target.get(association.foreignKey)
, 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.foreignKey);
if (targetId) {
return CounterUtil.increment(targetId, options);
}
},
update: function (target, options) {
var targetId = target.get(association.foreignKey)
, 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.foreignKey);
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.foreignKey);
});
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;
...@@ -7,11 +7,12 @@ var chai = require('chai') ...@@ -7,11 +7,12 @@ var chai = require('chai')
, Support = require(__dirname + '/support') , Support = require(__dirname + '/support')
, dialect = Support.getTestDialect() , dialect = Support.getTestDialect()
, Sequelize = Support.Sequelize , Sequelize = Support.Sequelize
, sqlite3 = require('sqlite3')
, fs = require('fs') , fs = require('fs')
, path = require('path'); , path = require('path');
if (dialect === 'sqlite') {
var sqlite3 = require('sqlite3')
}
describe(Support.getTestDialectTeaser('Configuration'), function() { describe(Support.getTestDialectTeaser('Configuration'), function() {
describe('Connections problems should fail with a nice message', function() { describe('Connections problems should fail with a nice message', function() {
......
'use strict';
/* jshint -W030 */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + '/../../../lib/data-types')
, Sequelize = require('../../../index')
, Promise = Sequelize.Promise;
describe(Support.getTestDialectTeaser('CounterCache'), function() {
it('adds an integer column', function() {
var User = this.sequelize.define('User', {})
, Group = this.sequelize.define('Group', {});
User.hasMany(Group, { counterCache: true });
expect(Object.keys(User.attributes)).to.contain('countGroups');
expect(User.attributes.countGroups.type instanceof DataTypes.INTEGER).to.be.ok;
});
it('supports `as`', function() {
var User = this.sequelize.define('User', {})
, Group = this.sequelize.define('Group', {});
User.hasMany(Group, { counterCache: { as: 'countDemGroups' } });
expect(Object.keys(User.attributes)).to.contain('countDemGroups');
});
it('inits at 0', function() {
var User = this.sequelize.define('User', {})
, Group = this.sequelize.define('Group', {});
User.hasMany(Group, { counterCache: true });
return this.sequelize.sync({ force: true }).then(function() {
return User.create();
}).then(function(user) {
expect(user.countGroups).to.equal(0);
});
});
describe('hooks', function() {
var User, Group;
beforeEach(function() {
User = this.sequelize.define('User', {});
Group = this.sequelize.define('Group', {});
User.hasMany(Group, { counterCache: true });
return this.sequelize.sync({ force: true });
});
it('increments', function() {
return User.create().then(function(user) {
expect(user.countGroups).to.equal(0);
return user.createGroup().return (user);
}).then(function(user) {
return User.findById(user.id);
}).then(function(user) {
expect(user.countGroups).to.equal(1);
});
});
it('decrements', function() {
var user;
return User.create().then(function(tmpUser) {
user = tmpUser;
return user.createGroup();
}).then(function(group) {
return group.destroy();
}).then(function() {
return user.reload();
}).then(function() {
expect(user.countGroups).to.equal(0);
});
});
it('works on update', function() {
var user, otherUser;
return User.create().then(function(tmpUser) {
otherUser = tmpUser;
return User.create();
}).then(function(tmpUser) {
user = tmpUser;
return user.createGroup();
}).tap(function() {
return user.reload();
}).tap(function() {
expect(user.countGroups).to.equal(1);
}).then(function(group) {
group.UserId = otherUser.id;
return group.save();
}).then(function() {
return Promise.all([user.reload(), otherUser.reload()]);
}).then(function() {
expect(user.countGroups).to.equal(0);
expect(otherUser.countGroups).to.equal(1);
});
});
});
});
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!