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

Commit a728a7aa by Jan Aagaard Meier

Fix default scope being overwritten. Closes #2087

1 parent aaf80ff9
......@@ -9,6 +9,7 @@ Notice: All 1.7.x changes are present in 2.0.x aswell
- [BUG] Hid `dottie.transform` on raw queries behind a flag (`nest`) [#2064](https://github.com/sequelize/sequelize/pull/2064)
- [BUG] Fixed problems with transcation parameter being removed / not passed on in associations [#1789](https://github.com/sequelize/sequelize/issues/1789) and [#1968](https://github.com/sequelize/sequelize/issues/1968)
- [BUG] Fix problem with minConnections. [#2048](https://github.com/sequelize/sequelize/issues/2048)
- [BUG] Fix default scope being overwritten [#2087](https://github.com/sequelize/sequelize/issues/2087)
- [INTERNALS] Replaced lingo with inflection
- [INTERNALS] Removed underscore.string dependency and moved a couple of helper functions from `Utils._` to `Utils`
- [INTERNALS] Update dependencies
......
......@@ -497,6 +497,8 @@ module.exports = (function() {
, argLength = arguments.length
, lastArg = arguments[argLength - 1];
self.scoped = true;
// Set defaults
scopeOptions = (typeof lastArg === 'object' && !Array.isArray(lastArg) ? lastArg : {}) || {}; // <-- for no arguments
scopeOptions.silent = (scopeOptions !== null && scopeOptions.hasOwnProperty('silent') ? scopeOptions.silent : true);
......
......@@ -554,18 +554,18 @@ module.exports = (function() {
return this.sequelize.query(sql, null, options);
};
QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) {
QueryInterface.prototype.select = function(model, tableName, options, queryOptions) {
options = options || {};
// See if we need to merge options and factory.scopeObj
// See if we need to merge options and model.scopeObj
// we're doing this on the QueryInterface level because it's a bridge between
// sequelize and the databases
if (Object.keys(factory.scopeObj).length > 0) {
if (model.options.defaultScope && Object.keys(model.options.defaultScope).length > 0) {
if (!!options) {
Utils.injectScope.call(factory, options, true);
Utils.injectScope.call(model, options, true);
}
var scopeObj = buildScope.call(factory);
var scopeObj = buildScope.call(model);
Object.keys(scopeObj).forEach(function(method) {
if (typeof scopeObj[method] === 'number' || !Utils._.isEmpty(scopeObj[method])) {
options[method] = scopeObj[method];
......@@ -575,7 +575,7 @@ module.exports = (function() {
options.lock = queryOptions.lock;
var sql = this.QueryGenerator.selectQuery(tableName, options, factory);
var sql = this.QueryGenerator.selectQuery(tableName, options, model);
queryOptions = Utils._.extend({}, queryOptions, {
include: options.include,
includeNames: options.includeNames,
......@@ -586,7 +586,7 @@ module.exports = (function() {
originalAttributes: options.originalAttributes
});
return this.sequelize.query(sql, factory, queryOptions);
return this.sequelize.query(sql, model, queryOptions);
};
QueryInterface.prototype.increment = function(dao, tableName, values, identifier, options) {
......
......@@ -82,7 +82,15 @@ var Utils = module.exports = {
var self = this;
scope = scope || {};
if (!this.scoped && self.options.defaultScope) {
self.scopeObj = Utils._.clone(self.options.defaultScope);
if (!Array.isArray(self.scopeObj.where)) {
self.scopeObj.where = [self.scopeObj.where];
}
} else {
self.scopeObj = self.scopeObj || {};
}
if (Array.isArray(scope.where)) {
self.scopeObj.where = self.scopeObj.where || [];
......
"use strict";
/* jshint camelcase: false */
/* jshint expr: true */
var chai = require('chai')
......@@ -5,13 +7,13 @@ var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + "/../../lib/data-types")
, datetime = require('chai-datetime')
, datetime = require('chai-datetime');
chai.use(datetime)
chai.config.includeStack = true
chai.use(datetime);
chai.config.includeStack = true;
describe(Support.getTestDialectTeaser("DAOFactory"), function () {
beforeEach(function(done) {
beforeEach(function() {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
secretValue: DataTypes.STRING,
......@@ -19,15 +21,13 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
intVal: DataTypes.INTEGER,
theDate: DataTypes.DATE,
aBool: DataTypes.BOOLEAN
})
});
this.User.sync({ force: true }).success(function() {
done()
})
})
return this.User.sync({ force: true });
});
describe('scopes', function() {
beforeEach(function(done) {
beforeEach(function() {
this.ScopeMe = this.sequelize.define('ScopeMe', {
username: Sequelize.STRING,
email: Sequelize.STRING,
......@@ -103,210 +103,222 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}
}
}
})
});
this.sequelize.sync({force: true}).success(function() {
return this.sequelize.sync({force: true}).then(function() {
var records = [
{username: 'dan', email: 'dan@sequelizejs.com', access_level: 5, other_value: 10},
{username: 'tobi', email: 'tobi@fakeemail.com', access_level: 10, other_value: 11},
{username: 'tony', email: 'tony@sequelizejs.com', access_level: 3, other_value: 7}
];
this.ScopeMe.bulkCreate(records).success(function() {
done()
})
}.bind(this))
})
it("should have no problems with escaping SQL", function(done) {
var self = this
this.ScopeMe.create({username: 'escape\'d', email: 'fake@fakemail.com'}).success(function(){
self.ScopeMe.scope('escape').all().success(function(users){
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(1)
return this.ScopeMe.bulkCreate(records);
}.bind(this));
});
it("should have no problems with escaping SQL", function() {
var self = this;
return this.ScopeMe.create({username: 'escape\'d', email: 'fake@fakemail.com'}).then(function(){
return self.ScopeMe.scope('escape').all().then(function(users){
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(1);
expect(users[0].username).to.equal('escape\'d');
done()
})
})
})
it("should be able to use a defaultScope if declared", function(done) {
this.ScopeMe.all().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(2)
expect([10,5].indexOf(users[0].access_level) !== -1).to.be.true
expect([10,5].indexOf(users[1].access_level) !== -1).to.be.true
expect(['dan', 'tobi'].indexOf(users[0].username) !== -1).to.be.true
expect(['dan', 'tobi'].indexOf(users[1].username) !== -1).to.be.true
done()
})
})
it("should be able to amend the default scope with a find object", function(done) {
this.ScopeMe.findAll({where: {username: 'dan'}}).success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(1)
expect(users[0].username).to.equal('dan')
done()
})
})
it("should be able to override the default scope", function(done) {
this.ScopeMe.scope('fakeEmail').findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(1)
expect(users[0].username).to.equal('tobi')
done()
})
})
it("should be able to combine two scopes", function(done) {
this.ScopeMe.scope(['sequelizeTeam', 'highValue']).findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(1)
expect(users[0].username).to.equal('dan')
done()
})
})
it("should be able to call a scope that's a function", function(done) {
this.ScopeMe.scope({method: ['actualValue', 11]}).findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(1)
expect(users[0].username).to.equal('tobi')
done()
})
})
it("should be able to handle multiple function scopes", function(done) {
this.ScopeMe.scope([{method: ['actualValue', 10]}, {method: ['complexFunction', 'dan', '5']}]).findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(1)
expect(users[0].username).to.equal('dan')
done()
})
})
it("should be able to stack the same field in the where clause", function(done) {
this.ScopeMe.scope(['canBeDan', 'canBeTony']).findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(2)
expect(['dan', 'tony'].indexOf(users[0].username) !== -1).to.be.true
expect(['dan', 'tony'].indexOf(users[1].username) !== -1).to.be.true
done()
})
})
it("should be able to merge scopes", function(done) {
this.ScopeMe.scope(['highValue', 'isTony', {merge: true, method: ['actualValue', 7]}]).findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(1)
expect(users[0].username).to.equal('tony')
done()
})
})
it("should give us the correct order if we declare an order in our scope", function(done) {
this.ScopeMe.scope('sequelizeTeam', 'orderScope').findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(2)
expect(users[0].username).to.equal('dan')
expect(users[1].username).to.equal('tony')
done()
})
})
it("should give us the correct order as well as a limit if we declare such in our scope", function(done) {
this.ScopeMe.scope(['orderScope', 'limitScope']).findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(2)
expect(users[0].username).to.equal('tobi')
expect(users[1].username).to.equal('dan')
done()
})
})
it("should have no problems combining scopes and traditional where object", function(done) {
this.ScopeMe.scope('sequelizeTeam').findAll({where: {other_value: 10}}).success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(1)
expect(users[0].username).to.equal('dan')
expect(users[0].access_level).to.equal(5)
expect(users[0].other_value).to.equal(10)
done()
})
})
it("should be able to remove all scopes", function(done) {
this.ScopeMe.scope(null).findAll().success(function(users) {
expect(users).to.be.an.instanceof(Array)
expect(users.length).to.equal(3)
done()
})
})
it("should have no problem performing findOrCreate", function(done) {
this.ScopeMe.findOrCreate({username: 'fake'}).spread(function(user) {
expect(user.username).to.equal('fake')
done()
})
})
it("should be able to hold multiple scope objects", function(done) {
});
});
});
it("should be able to use a defaultScope if declared", function() {
return this.ScopeMe.all().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(2);
expect([10,5].indexOf(users[0].access_level) !== -1).to.be.true;
expect([10,5].indexOf(users[1].access_level) !== -1).to.be.true;
expect(['dan', 'tobi'].indexOf(users[0].username) !== -1).to.be.true;
expect(['dan', 'tobi'].indexOf(users[1].username) !== -1).to.be.true;
});
});
it("should be able to amend the default scope with a find object", function() {
return this.ScopeMe.findAll({where: {username: 'dan'}}).then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(1);
expect(users[0].username).to.equal('dan');
});
});
it("should be able to override the default scope", function() {
return this.ScopeMe.scope('fakeEmail').findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(1);
expect(users[0].username).to.equal('tobi');
});
});
it("should be able to combine two scopes", function() {
return this.ScopeMe.scope(['sequelizeTeam', 'highValue']).findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(1);
expect(users[0].username).to.equal('dan');
});
});
it("should be able to call a scope that's a function", function() {
return this.ScopeMe.scope({method: ['actualValue', 11]}).findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(1);
expect(users[0].username).to.equal('tobi');
});
});
it("should be able to handle multiple function scopes", function() {
return this.ScopeMe.scope([{method: ['actualValue', 10]}, {method: ['complexFunction', 'dan', '5']}]).findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(1);
expect(users[0].username).to.equal('dan');
});
});
it("should be able to stack the same field in the where clause", function() {
return this.ScopeMe.scope(['canBeDan', 'canBeTony']).findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(2);
expect(['dan', 'tony'].indexOf(users[0].username) !== -1).to.be.true;
expect(['dan', 'tony'].indexOf(users[1].username) !== -1).to.be.true;
});
});
it("should be able to merge scopes", function() {
return this.ScopeMe.scope(['highValue', 'isTony', {merge: true, method: ['actualValue', 7]}]).findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(1);
expect(users[0].username).to.equal('tony');
});
});
describe("should not overwrite", function () {
it("default scope with values from previous finds", function () {
return this.ScopeMe.findAll({ where: { other_value: 10 }}).bind(this).then(function (users) {
expect(users).to.have.length(1);
return this.ScopeMe.findAll();
}).then(function (users) {
// This should not have other_value: 10
expect(users).to.have.length(2);
});
});
it("other scopes with values from previous finds", function () {
return this.ScopeMe.scope('highValue').findAll({ where: { access_level: 10 }}).bind(this).then(function (users) {
expect(users).to.have.length(1);
return this.ScopeMe.scope('highValue').findAll();
}).then(function (users) {
// This should not have other_value: 10
expect(users).to.have.length(2);
});
});
it("function scopes", function () {
return this.ScopeMe.scope({method: ['actualValue', 11]}).findAll().bind(this).then(function(users) {
expect(users).to.have.length(1);
expect(users[0].other_value).to.equal(11);
return this.ScopeMe.scope({method: ['actualValue', 10]}).findAll();
}).then(function(users) {
expect(users).to.have.length(1);
expect(users[0].other_value).to.equal(10);
});
});
});
it("should give us the correct order if we declare an order in our scope", function() {
return this.ScopeMe.scope('sequelizeTeam', 'orderScope').findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(2);
expect(users[0].username).to.equal('dan');
expect(users[1].username).to.equal('tony');
});
});
it("should give us the correct order as well as a limit if we declare such in our scope", function() {
return this.ScopeMe.scope(['orderScope', 'limitScope']).findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(2);
expect(users[0].username).to.equal('tobi');
expect(users[1].username).to.equal('dan');
});
});
it("should have no problems combining scopes and traditional where object", function() {
return this.ScopeMe.scope('sequelizeTeam').findAll({where: {other_value: 10}}).then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(1);
expect(users[0].username).to.equal('dan');
expect(users[0].access_level).to.equal(5);
expect(users[0].other_value).to.equal(10);
});
});
it("should be able to remove all scopes", function() {
return this.ScopeMe.scope(null).findAll().then(function(users) {
expect(users).to.be.an.instanceof(Array);
expect(users.length).to.equal(3);
});
});
it("should have no problem performing findOrCreate", function() {
return this.ScopeMe.findOrCreate({username: 'fake'}).spread(function(user) {
expect(user.username).to.equal('fake');
});
});
it("should be able to hold multiple scope objects", function() {
var sequelizeTeam = this.ScopeMe.scope('sequelizeTeam', 'orderScope')
, tobi = this.ScopeMe.scope({method: ['actualValue', 11]})
sequelizeTeam.all().success(function(team) {
tobi.all().success(function(t) {
expect(team).to.be.an.instanceof(Array)
expect(team.length).to.equal(2)
expect(team[0].username).to.equal('dan')
expect(team[1].username).to.equal('tony')
expect(t).to.be.an.instanceof(Array)
expect(t.length).to.equal(1)
expect(t[0].username).to.equal('tobi')
done()
})
})
})
it("should gracefully omit any scopes that don't exist", function(done) {
this.ScopeMe.scope('sequelizeTeam', 'orderScope', 'doesntexist').all().success(function(team) {
expect(team).to.be.an.instanceof(Array)
expect(team.length).to.equal(2)
expect(team[0].username).to.equal('dan')
expect(team[1].username).to.equal('tony')
done()
})
})
it("should gracefully omit any scopes that don't exist through an array", function(done) {
this.ScopeMe.scope(['sequelizeTeam', 'orderScope', 'doesntexist']).all().success(function(team) {
expect(team).to.be.an.instanceof(Array)
expect(team.length).to.equal(2)
expect(team[0].username).to.equal('dan')
expect(team[1].username).to.equal('tony')
done()
})
})
it("should gracefully omit any scopes that don't exist through an object", function(done) {
this.ScopeMe.scope('sequelizeTeam', 'orderScope', {method: 'doesntexist'}).all().success(function(team) {
expect(team).to.be.an.instanceof(Array)
expect(team.length).to.equal(2)
expect(team[0].username).to.equal('dan')
expect(team[1].username).to.equal('tony')
done()
})
})
it("should emit an error for scopes that don't exist with silent: false", function(done) {
try {
this.ScopeMe.scope('doesntexist', {silent: false})
} catch (err) {
expect(err.message).to.equal('Invalid scope doesntexist called.')
done()
}
})
})
})
\ No newline at end of file
, tobi = this.ScopeMe.scope({method: ['actualValue', 11]});
return sequelizeTeam.all().then(function(team) {
return tobi.all().then(function(t) {
expect(team).to.be.an.instanceof(Array);
expect(team.length).to.equal(2);
expect(team[0].username).to.equal('dan');
expect(team[1].username).to.equal('tony');
expect(t).to.be.an.instanceof(Array);
expect(t.length).to.equal(1);
expect(t[0].username).to.equal('tobi');
});
});
});
it("should gracefully omit any scopes that don't exist", function() {
return this.ScopeMe.scope('sequelizeTeam', 'orderScope', 'doesntexist').all().then(function(team) {
expect(team).to.be.an.instanceof(Array);
expect(team.length).to.equal(2);
expect(team[0].username).to.equal('dan');
expect(team[1].username).to.equal('tony');
});
});
it("should gracefully omit any scopes that don't exist through an array", function() {
return this.ScopeMe.scope(['sequelizeTeam', 'orderScope', 'doesntexist']).all().then(function(team) {
expect(team).to.be.an.instanceof(Array);
expect(team.length).to.equal(2);
expect(team[0].username).to.equal('dan');
expect(team[1].username).to.equal('tony');
});
});
it("should gracefully omit any scopes that don't exist through an object", function() {
return this.ScopeMe.scope('sequelizeTeam', 'orderScope', {method: 'doesntexist'}).all().then(function(team) {
expect(team).to.be.an.instanceof(Array);
expect(team.length).to.equal(2);
expect(team[0].username).to.equal('dan');
expect(team[1].username).to.equal('tony');
});
});
it("should emit an error for scopes that don't exist with silent: false", function() {
expect(this.ScopeMe.scope.bind(this.ScopeMe, 'doesntexist', {silent: false})).to.throw('Invalid scope doesntexist called.');
});
});
});
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!