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

Commit b503b51e by Jan Aagaard Meier

Apply attributes when including a scoped model. Closes #4625

1 parent f6b78555
# Next # Next
- [FIXED] Partial rollback of datatype validations by hiding it behind the `typeValidation` flag. - [FIXED] Partial rollback of datatype validations by hiding it behind the `typeValidation` flag.
- [FIXED] Don't try to select the primary key for models without primary key [#4607](https://github.com/sequelize/sequelize/issues/4607) - [FIXED] Don't try to select the primary key for models without primary key [#4607](https://github.com/sequelize/sequelize/issues/4607)
- [FIXED] Apply `attributes` when including a scoped model. [#4625](https://github.com/sequelize/sequelize/issues/4625)
# 3.11.0 # 3.11.0
- [INTERNALS] Updated dependencies [#4594](https://github.com/sequelize/sequelize/pull/4594) - [INTERNALS] Updated dependencies [#4594](https://github.com/sequelize/sequelize/pull/4594)
......
...@@ -241,6 +241,10 @@ var findAutoIncrementField = function() { ...@@ -241,6 +241,10 @@ var findAutoIncrementField = function() {
}; };
function conformOptions(options, self) { function conformOptions(options, self) {
if (self) {
self.$expandAttributes(options);
}
if (!options.include) { if (!options.include) {
return; return;
} }
...@@ -520,7 +524,7 @@ validateIncludedElement = function(include, tableNames, options) { ...@@ -520,7 +524,7 @@ validateIncludedElement = function(include, tableNames, options) {
tableNames[include.model.getTableName()] = true; tableNames[include.model.getTableName()] = true;
if (include.attributes && !options.raw) { if (include.attributes && !options.raw) {
include.model.$handleAttributes(include); include.model.$expandAttributes(include);
// Need to make sure virtuals are mapped before setting originalAttributes // Need to make sure virtuals are mapped before setting originalAttributes
include = Utils.mapFinderOptions(include, include.model); include = Utils.mapFinderOptions(include, include.model);
...@@ -542,14 +546,11 @@ validateIncludedElement = function(include, tableNames, options) { ...@@ -542,14 +546,11 @@ validateIncludedElement = function(include, tableNames, options) {
} }
} else { } else {
include = Utils.mapFinderOptions(include, include.model); include = Utils.mapFinderOptions(include, include.model);
if (!include.attributes) {
include.attributes = Object.keys(include.model.tableAttributes);
}
} }
// pseudo include just needed the attribute logic, return // pseudo include just needed the attribute logic, return
if (include._pseudo) { if (include._pseudo) {
include.attributes = Object.keys(include.model.tableAttributes);
return Utils.mapFinderOptions(include, include.model); return Utils.mapFinderOptions(include, include.model);
} }
...@@ -607,6 +608,11 @@ validateIncludedElement = function(include, tableNames, options) { ...@@ -607,6 +608,11 @@ validateIncludedElement = function(include, tableNames, options) {
Model.$injectScope(model.$scope, include); Model.$injectScope(model.$scope, include);
// This check should happen after injecting the scope, since the scope may contain a .attributes
if (!include.attributes) {
include.attributes = Object.keys(include.model.tableAttributes);
}
include = Utils.mapFinderOptions(include, include.model); include = Utils.mapFinderOptions(include, include.model);
if (include.required === undefined) { if (include.required === undefined) {
...@@ -689,14 +695,14 @@ Model.prototype.init = function(modelManager) { ...@@ -689,14 +695,14 @@ Model.prototype.init = function(modelManager) {
this.$scope = this.options.defaultScope || {}; this.$scope = this.options.defaultScope || {};
if (_.isPlainObject(this.$scope)) { if (_.isPlainObject(this.$scope)) {
conformOptions(this.$scope); conformOptions(this.$scope, this);
} }
_.each(this.options.scopes, function (scope) { _.each(this.options.scopes, function (scope) {
if (_.isPlainObject(scope)) { if (_.isPlainObject(scope)) {
conformOptions(scope); conformOptions(scope, this);
} }
}); }, this);
// Instance prototype // Instance prototype
this.Instance = function() { this.Instance = function() {
...@@ -1096,7 +1102,7 @@ Model.prototype.addScope = function (name, scope, options) { ...@@ -1096,7 +1102,7 @@ Model.prototype.addScope = function (name, scope, options) {
throw new Error('The scope ' + name + ' already exists. Pass { override: true } as options to silence this error'); throw new Error('The scope ' + name + ' already exists. Pass { override: true } as options to silence this error');
} }
conformOptions(scope); conformOptions(scope, this);
if (name === 'defaultScope') { if (name === 'defaultScope') {
this.options.defaultScope = this.$scope = scope; this.options.defaultScope = this.$scope = scope;
...@@ -1190,7 +1196,7 @@ Model.prototype.scope = function(option) { ...@@ -1190,7 +1196,7 @@ Model.prototype.scope = function(option) {
if (_.isFunction(scope)) { if (_.isFunction(scope)) {
scope = scope(); scope = scope();
conformOptions(scope); conformOptions(scope, self);
} }
} }
} }
...@@ -1346,8 +1352,6 @@ Model.prototype.findAll = function(options) { ...@@ -1346,8 +1352,6 @@ Model.prototype.findAll = function(options) {
return this.runHooks('beforeFindAfterExpandIncludeAll', options); return this.runHooks('beforeFindAfterExpandIncludeAll', options);
} }
}).then(function() { }).then(function() {
this.$handleAttributes(options);
if (options.include) { if (options.include) {
options.hasJoin = true; options.hasJoin = true;
...@@ -1360,6 +1364,10 @@ Model.prototype.findAll = function(options) { ...@@ -1360,6 +1364,10 @@ Model.prototype.findAll = function(options) {
} }
} }
if (!options.attributes) {
options.attributes = Object.keys(this.tableAttributes);
}
// whereCollection is used for non-primary key updates // whereCollection is used for non-primary key updates
this.options.whereCollection = options.where || null; this.options.whereCollection = options.where || null;
...@@ -2579,10 +2587,10 @@ Model.prototype.$getDefaultTimestamp = function(attr) { ...@@ -2579,10 +2587,10 @@ Model.prototype.$getDefaultTimestamp = function(attr) {
return undefined; return undefined;
}; };
Model.prototype.$handleAttributes = function (options) { Model.prototype.$expandAttributes = function (options) {
var attributes = Array.isArray(options.attributes) ? options.attributes : Object.keys(this.tableAttributes);
if (_.isPlainObject(options.attributes)) { if (_.isPlainObject(options.attributes)) {
var attributes = Object.keys(this.tableAttributes);
if (options.attributes.exclude) { if (options.attributes.exclude) {
attributes = attributes.filter(function (elem) { attributes = attributes.filter(function (elem) {
return options.attributes.exclude.indexOf(elem) === -1; return options.attributes.exclude.indexOf(elem) === -1;
...@@ -2591,9 +2599,9 @@ Model.prototype.$handleAttributes = function (options) { ...@@ -2591,9 +2599,9 @@ Model.prototype.$handleAttributes = function (options) {
if (options.attributes.include) { if (options.attributes.include) {
attributes = attributes.concat(options.attributes.include); attributes = attributes.concat(options.attributes.include);
} }
}
options.attributes = attributes; options.attributes = attributes;
}
}; };
// Inject current scope into options. Includes should have been conformed (conformOptions) before calling this // Inject current scope into options. Includes should have been conformed (conformOptions) before calling this
......
...@@ -157,6 +157,9 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -157,6 +157,9 @@ describe(Support.getTestDialectTeaser('Model'), function() {
where: { that: false }, where: { that: false },
limit: 12 limit: 12
}, },
attr: {
attributes: ['baz']
},
foobar: { foobar: {
where: { where: {
bar: 42 bar: 42
...@@ -189,6 +192,15 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -189,6 +192,15 @@ describe(Support.getTestDialectTeaser('Model'), function() {
expect(options.include[0]).to.have.property('limit').which.equals(12); expect(options.include[0]).to.have.property('limit').which.equals(12);
}); });
it('adds the attributes from a scoped model', function () {
var options = Sequelize.Model.$validateIncludedElements({
model: this.User,
include: [{ model: this.Project.scope('attr') }]
});
expect(options.include[0]).to.have.property('attributes').which.deep.equals(['baz']);
});
it('merges where with the where from a scoped model', function () { it('merges where with the where from a scoped model', function () {
var options = Sequelize.Model.$validateIncludedElements({ var options = Sequelize.Model.$validateIncludedElements({
model: this.User, model: this.User,
......
...@@ -217,6 +217,20 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -217,6 +217,20 @@ describe(Support.getTestDialectTeaser('Model'), function() {
include: [{ model: Project }] include: [{ model: Project }]
}); });
}); });
it('works with exclude and include attributes', function () {
Company.addScope('newIncludeScope', {
attributes: {
include: ['foobar'],
exclude: ['createdAt']
}
});
expect(Company.scope('newIncludeScope').$scope).to.deep.equal({
attributes: ['id', 'updatedAt', 'foobar']
});
});
}); });
describe('$injectScope', function () { describe('$injectScope', function () {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!