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

Commit 80d19ab7 by Mick Hansen

feat(association/scope): include support for 1:M associaton scopes

1 parent c2316b68
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
- [BUG] Fixed an issue with foreign key object syntax for hasOne and belongsTo - [BUG] Fixed an issue with foreign key object syntax for hasOne and belongsTo
- [FEATURE] Added `field` and `name` to the object form of foreign key definitions - [FEATURE] Added `field` and `name` to the object form of foreign key definitions
- [FEATURE] Added support for calling `Promise.done`, thus explicitly ending the promise chain by calling done with no arguments. Done with a function argument still continues the promise chain, to maintain BC. - [FEATURE] Added support for calling `Promise.done`, thus explicitly ending the promise chain by calling done with no arguments. Done with a function argument still continues the promise chain, to maintain BC.
- [FEATURE] Added `scope` to hasMany association definitions, provides default values to association setters/finders [#2268](https://github.com/sequelize/sequelize/pull/2268)
#### Backwards compatability changes #### Backwards compatability changes
- The `fieldName` property, used in associations with a foreign key object `(A.hasMany(B, { foreignKey: { ... }})`, has been renamed to `name` to avoid confusion with `field`. - The `fieldName` property, used in associations with a foreign key object `(A.hasMany(B, { foreignKey: { ... }})`, has been renamed to `name` to avoid confusion with `field`.
- When using association N:M getters the included join table entry is now named singularly, this is now the same as includes.
# v2.0.0-dev13 # v2.0.0-dev13
We are working our way to the first 2.0.0 release candidate. We are working our way to the first 2.0.0 release candidate.
......
...@@ -230,7 +230,7 @@ Mixin.belongsTo = singleLinked(BelongsTo); ...@@ -230,7 +230,7 @@ Mixin.belongsTo = singleLinked(BelongsTo);
* @param {Model|string} [options.through] The name of the table that is used to join source and target in n:m associations. Can also be a sequelize model if you want to define the junction table yourself and add extra attributes to it. * @param {Model|string} [options.through] The name of the table that is used to join source and target in n:m associations. Can also be a sequelize model if you want to define the junction table yourself and add extra attributes to it.
* @param {string|object} [options.as] The alias of this model. If you provide a string, it should be plural, and will be singularized using node.inflection. If you want to control the singular version yourself, provide an object with `plural` and `singular` keys. See also the `name` option passed to `sequelize.define`. If you create multiple associations between the same tables, you should provide an alias to be able to distinguish between them. If you provide an alias when creating the assocition, you should provide the same alias when eager loading and when getting assocated models. Defaults to the pluralized name of target * @param {string|object} [options.as] The alias of this model. If you provide a string, it should be plural, and will be singularized using node.inflection. If you want to control the singular version yourself, provide an object with `plural` and `singular` keys. See also the `name` option passed to `sequelize.define`. If you create multiple associations between the same tables, you should provide an alias to be able to distinguish between them. If you provide an alias when creating the assocition, you should provide the same alias when eager loading and when getting assocated models. Defaults to the pluralized name of target
* @param {string|object} [options.foreignKey] The name of the foreign key in the target table / join table or an object representing the type definition for the foreign column (see `Sequelize.define` for syntax). When using an object, you can add a `name` property to set the name of the colum. Defaults to the name of source + primary key of source * @param {string|object} [options.foreignKey] The name of the foreign key in the target table / join table or an object representing the type definition for the foreign column (see `Sequelize.define` for syntax). When using an object, you can add a `name` property to set the name of the colum. Defaults to the name of source + primary key of source
* @param {object} [options.scope] A key/value set that will be used for association create and find defaults. (only works for 1:m) * @param {object} [options.scope] A key/value set that will be used for association create and find defaults.
* @param {string} [options.onDelete='SET NULL|CASCADE'] Cascade if this is a n:m, and set null if it is a 1:m * @param {string} [options.onDelete='SET NULL|CASCADE'] Cascade if this is a n:m, and set null if it is a 1:m
* @param {string} [options.onUpdate='CASCADE'] * @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key. * @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
......
...@@ -1783,6 +1783,10 @@ module.exports = (function() { ...@@ -1783,6 +1783,10 @@ module.exports = (function() {
include.required = !!include.where; include.required = !!include.where;
} }
if (include.association.scope) {
include.where = include.where ? new Util.and(include.where, include.association.scope) : include.association.scope;
}
// Validate child includes // Validate child includes
if (include.hasOwnProperty('include')) { if (include.hasOwnProperty('include')) {
validateIncludedElements.call(include.model, include, tableNames); validateIncludedElements.call(include.model, include, tableNames);
......
...@@ -28,6 +28,11 @@ describe(Support.getTestDialectTeaser("associations"), function() { ...@@ -28,6 +28,11 @@ describe(Support.getTestDialectTeaser("associations"), function() {
} }
} }
}); });
this.Tag = this.sequelize.define('tag', {
name: Sequelize.STRING,
taggable: Sequelize.STRING,
taggable_id: Sequelize.INTEGER
});
this.Post.hasMany(this.Comment, { this.Post.hasMany(this.Comment, {
foreignKey: 'commentable_id', foreignKey: 'commentable_id',
...@@ -72,7 +77,8 @@ describe(Support.getTestDialectTeaser("associations"), function() { ...@@ -72,7 +77,8 @@ describe(Support.getTestDialectTeaser("associations"), function() {
}); });
}); });
it('should create associations and find association with scope values', function () { describe('1:M', function () {
it('should create, find and include associations with scope values', function () {
var self = this; var self = this;
return this.sequelize.sync({force: true}).then(function () { return this.sequelize.sync({force: true}).then(function () {
return Promise.join( return Promise.join(
...@@ -131,6 +137,32 @@ describe(Support.getTestDialectTeaser("associations"), function() { ...@@ -131,6 +137,32 @@ describe(Support.getTestDialectTeaser("associations"), function() {
expect(post.Model).to.equal(self.Post); expect(post.Model).to.equal(self.Post);
expect(image.Model).to.equal(self.Image); expect(image.Model).to.equal(self.Image);
expect(question.Model).to.equal(self.Question); expect(question.Model).to.equal(self.Question);
}).then(function () {
return Promise.join(
self.Post.find({
include: [self.Comment]
}),
self.Image.find({
include: [self.Comment]
}),
self.Question.find({
include: [self.Comment]
})
);
}).spread(function (post, image, question) {
expect(post.comments.length).to.equal(1);
expect(post.comments[0].get('title')).to.equal('I am a post comment');
expect(image.comments.length).to.equal(1);
expect(image.comments[0].get('title')).to.equal('I am a image comment');
expect(question.comments.length).to.equal(1);
expect(question.comments[0].get('title')).to.equal('I am a question comment');
});
});
});
describe('N:M', function () {
it.skip('should create associations and find association with scope values', function () {
}); });
}); });
}); });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!