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

Commit 3f74fec0 by Mick Hansen

Merge branch 'ErikvdVen-master'

2 parents 040e24c3 4887b840
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
- [BUG] Fixed issue with paranoid deletes and `deletedAt` with a custom field. - [BUG] Fixed issue with paranoid deletes and `deletedAt` with a custom field.
- [BUG] No longer crahes on `where: []` - [BUG] No longer crahes on `where: []`
- [FEATURE] Validations are now enabled by default for upsert. - [FEATURE] Validations are now enabled by default for upsert.
- [FEATURE] Preliminary support for `include.through.where`
# 2.0.0-rc7 # 2.0.0-rc7
- [FEATURE] Throw an error if no where clause is given to `Model.destroy()`. - [FEATURE] Throw an error if no where clause is given to `Model.destroy()`.
......
...@@ -974,7 +974,9 @@ module.exports = (function() { ...@@ -974,7 +974,9 @@ module.exports = (function() {
, sourceJoinOn , sourceJoinOn
, targetJoinOn , targetJoinOn
, targetWhere; , targetWhere
, throughWhere;
if (options.includeIgnoreAttributes !== false) { if (options.includeIgnoreAttributes !== false) {
// Through includes are always hasMany, so we need to add the attributes to the mainAttributes no matter what (Real join will never be executed in subquery) // Through includes are always hasMany, so we need to add the attributes to the mainAttributes no matter what (Real join will never be executed in subquery)
...@@ -991,12 +993,21 @@ module.exports = (function() { ...@@ -991,12 +993,21 @@ module.exports = (function() {
targetJoinOn = self.quoteIdentifier(tableTarget) + '.' + self.quoteIdentifier(attrTarget) + ' = '; targetJoinOn = self.quoteIdentifier(tableTarget) + '.' + self.quoteIdentifier(attrTarget) + ' = ';
targetJoinOn += self.quoteIdentifier(throughAs) + '.' + self.quoteIdentifier(identTarget); targetJoinOn += self.quoteIdentifier(throughAs) + '.' + self.quoteIdentifier(identTarget);
if (include.through.where) {
throughWhere = self.getWhereConditions(include.through.where, self.sequelize.literal(self.quoteIdentifier(throughAs)), include.through.model);
}
if (self._dialect.supports.joinTableDependent) { if (self._dialect.supports.joinTableDependent) {
// Generate a wrapped join so that the through table join can be dependent on the target join // Generate a wrapped join so that the through table join can be dependent on the target join
joinQueryItem += joinType + '('; joinQueryItem += joinType + '(';
joinQueryItem += self.quoteTable(throughTable, throughAs); joinQueryItem += self.quoteTable(throughTable, throughAs);
joinQueryItem += joinType + self.quoteTable(table, as) + ' ON '; joinQueryItem += joinType + self.quoteTable(table, as) + ' ON ';
joinQueryItem += targetJoinOn; joinQueryItem += targetJoinOn;
if (throughWhere) {
joinQueryItem += ' AND ' + throughWhere;
}
joinQueryItem += ') ON '+sourceJoinOn; joinQueryItem += ') ON '+sourceJoinOn;
} else { } else {
// Generate join SQL for left side of through // Generate join SQL for left side of through
...@@ -1006,11 +1017,18 @@ module.exports = (function() { ...@@ -1006,11 +1017,18 @@ module.exports = (function() {
// Generate join SQL for right side of through // Generate join SQL for right side of through
joinQueryItem += joinType + self.quoteTable(table, as) + ' ON '; joinQueryItem += joinType + self.quoteTable(table, as) + ' ON ';
joinQueryItem += targetJoinOn; joinQueryItem += targetJoinOn;
if (throughWhere) {
joinQueryItem += ' AND ' + throughWhere;
}
} }
if (include.where) { if (include.where || include.through.where) {
targetWhere = self.getWhereConditions(include.where, self.sequelize.literal(self.quoteIdentifier(as)), include.model, whereOptions); if (include.where) {
joinQueryItem += ' AND ' + targetWhere; targetWhere = self.getWhereConditions(include.where, self.sequelize.literal(self.quoteIdentifier(as)), include.model, whereOptions);
joinQueryItem += ' AND ' + targetWhere;
}
if (subQuery && include.required) { if (subQuery && include.required) {
if (!options.where) options.where = {}; if (!options.where) options.where = {};
(function (include) { (function (include) {
...@@ -1050,12 +1068,13 @@ module.exports = (function() { ...@@ -1050,12 +1068,13 @@ module.exports = (function() {
include: topInclude.include, include: topInclude.include,
_pseudo: true _pseudo: true
}], }],
where: { where: self.sequelize.and(
$join: self.sequelize.asIs([ self.sequelize.asIs([
self.quoteTable(topParent.model.name) + '.' + self.quoteIdentifier(topParent.model.primaryKeyAttributes[0]), self.quoteTable(topParent.model.name) + '.' + self.quoteIdentifier(topParent.model.primaryKeyAttributes[0]),
self.quoteIdentifier(topInclude.through.model.name) + '.' + self.quoteIdentifier(topInclude.association.identifierField) self.quoteIdentifier(topInclude.through.model.name) + '.' + self.quoteIdentifier(topInclude.association.identifierField)
].join(" = ")) ].join(" = ")),
}, topInclude.through.where
),
limit: 1, limit: 1,
includeIgnoreAttributes: false includeIgnoreAttributes: false
}, topInclude.through.model); }, topInclude.through.model);
......
...@@ -1750,6 +1750,58 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -1750,6 +1750,58 @@ describe(Support.getTestDialectTeaser('Include'), function() {
}); });
}); });
it('should be possible to select on columns inside a through table', function(done) {
var self = this;
this.fixtureA(function() {
self.models.Product.findAll({
attributes: ['title'],
include: [
{
model: self.models.Tag,
through: {
where: {
ProductId: 3
}
},
required: true
}
]
}).done(function(err, products) {
expect(err).not.to.be.ok;
expect(products).have.length(1);
done();
});
});
});
it('should be possible to select on columns inside a through table and a limit', function(done) {
var self = this;
this.fixtureA(function() {
self.models.Product.findAll({
attributes: ['title'],
include: [
{
model: self.models.Tag,
through: {
where: {
ProductId: 3
}
},
required: true
}
],
limit: 5
}).done(function(err, products) {
expect(err).not.to.be.ok;
expect(products).have.length(1);
done();
});
});
});
// Test case by @eshell // Test case by @eshell
it('should be possible not to include the main id in the attributes', function(done) { it('should be possible not to include the main id in the attributes', function(done) {
var Member = this.sequelize.define('Member', { var Member = this.sequelize.define('Member', {
...@@ -1999,18 +2051,18 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -1999,18 +2051,18 @@ describe(Support.getTestDialectTeaser('Include'), function() {
}); });
}); });
}); });
it('should work on a nested set of required 1:1 relations', function () { it('should work on a nested set of required 1:1 relations', function () {
var Person = this.sequelize.define("Person", { var Person = this.sequelize.define("Person", {
name: { name: {
type : Sequelize.STRING, type : Sequelize.STRING,
allowNull : false allowNull : false
} }
}); });
var UserPerson = this.sequelize.define("UserPerson", { var UserPerson = this.sequelize.define("UserPerson", {
PersonId: { PersonId: {
type : Sequelize.INTEGER, type : Sequelize.INTEGER,
primaryKey : true primaryKey : true
}, },
...@@ -2020,8 +2072,8 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -2020,8 +2072,8 @@ describe(Support.getTestDialectTeaser('Include'), function() {
}); });
var User = this.sequelize.define("User", { var User = this.sequelize.define("User", {
UserPersonId: { UserPersonId: {
type : Sequelize.INTEGER, type : Sequelize.INTEGER,
primaryKey : true primaryKey : true
}, },
...@@ -2032,20 +2084,20 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -2032,20 +2084,20 @@ describe(Support.getTestDialectTeaser('Include'), function() {
} }
}); });
UserPerson.belongsTo(Person, { UserPerson.belongsTo(Person, {
foreignKey: { foreignKey: {
allowNull: false allowNull: false
}, },
onDelete: 'CASCADE' onDelete: 'CASCADE'
}); });
Person.hasOne(UserPerson, { Person.hasOne(UserPerson, {
foreignKey: { foreignKey: {
allowNull: false allowNull: false
}, },
onDelete: 'CASCADE' onDelete: 'CASCADE'
}); });
User.belongsTo(UserPerson, { User.belongsTo(UserPerson, {
foreignKey: { foreignKey: {
name: 'UserPersonId', name: 'UserPersonId',
allowNull: false allowNull: false
...@@ -2053,7 +2105,7 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -2053,7 +2105,7 @@ describe(Support.getTestDialectTeaser('Include'), function() {
onDelete: 'CASCADE' onDelete: 'CASCADE'
}); });
UserPerson.hasOne(User, { UserPerson.hasOne(User, {
foreignKey: { foreignKey: {
name: 'UserPersonId', name: 'UserPersonId',
allowNull: false allowNull: false
}, },
...@@ -2063,12 +2115,12 @@ describe(Support.getTestDialectTeaser('Include'), function() { ...@@ -2063,12 +2115,12 @@ describe(Support.getTestDialectTeaser('Include'), function() {
return this.sequelize.sync({force: true}).then(function () { return this.sequelize.sync({force: true}).then(function () {
return Person.findAll({ return Person.findAll({
offset : 0, offset : 0,
limit : 20, limit : 20,
attributes : ['id', 'name'], attributes : ['id', 'name'],
include : [{ include : [{
model : UserPerson, model : UserPerson,
required : true, required : true,
attributes : ['rank'], attributes : ['rank'],
include : [{ include : [{
model : User, model : User,
required : true, required : true,
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!