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

Commit 6501dca6 by Mick Hansen

Merge pull request #1555 from sequelize/perf

Performance improvements on includes
2 parents 6dbdde03 cfd0db95
...@@ -126,7 +126,7 @@ module.exports = (function() { ...@@ -126,7 +126,7 @@ module.exports = (function() {
this._timestampAttributes.createdAt = Utils._.underscoredIf(this.options.createdAt, this.options.underscored) this._timestampAttributes.createdAt = Utils._.underscoredIf(this.options.createdAt, this.options.underscored)
} }
if (this.options.updatedAt) { if (this.options.updatedAt) {
this._timestampAttributes.updatedAt = Utils._.underscoredIf(this.options.updatedAt, this.options.underscored) this._timestampAttributes.updatedAt = Utils._.underscoredIf(this.options.updatedAt, this.options.underscored)
} }
if (this.options.paranoid && this.options.deletedAt) { if (this.options.paranoid && this.options.deletedAt) {
this._timestampAttributes.deletedAt = Utils._.underscoredIf(this.options.deletedAt, this.options.underscored) this._timestampAttributes.deletedAt = Utils._.underscoredIf(this.options.deletedAt, this.options.underscored)
......
...@@ -13,8 +13,6 @@ module.exports = (function() { ...@@ -13,8 +13,6 @@ module.exports = (function() {
this._previousDataValues = {} this._previousDataValues = {}
this.__options = this.Model.options this.__options = this.Model.options
this.options = options this.options = options
this.hasPrimaryKeys = this.Model.options.hasPrimaryKeys
this.__eagerlyLoadedAssociations = []
this.isNewRecord = options.isNewRecord this.isNewRecord = options.isNewRecord
initValues.call(this, values, options); initValues.call(this, values, options);
...@@ -161,7 +159,9 @@ module.exports = (function() { ...@@ -161,7 +159,9 @@ module.exports = (function() {
} }
} else { } else {
options || (options = {}) options || (options = {})
originalValue = this.dataValues[key] if (!options.raw) {
originalValue = this.dataValues[key]
}
// If not raw, and there's a customer setter // If not raw, and there's a customer setter
if (!options.raw && this._customSetters[key]) { if (!options.raw && this._customSetters[key]) {
...@@ -169,24 +169,32 @@ module.exports = (function() { ...@@ -169,24 +169,32 @@ module.exports = (function() {
} else { } else {
// Check if we have included models, and if this key matches the include model names/aliases // Check if we have included models, and if this key matches the include model names/aliases
if (this.options && this.options.include && this.options.includeNames.indexOf(key) !== -1) { if (this.options && this.options.include && this.options.includeNames.indexOf(key) !== -1 && value) {
// Pass it on to the include handler // Pass it on to the include handler
this._setInclude(key, value, options) this._setInclude(key, value, options)
return return
} else { } else {
// If not raw, and attribute is not in model definition, return // Bunch of stuff we won't do when its raw
if (!options.raw && !this._isAttribute(key)) { if (!options.raw) {
return; // If attribute is not in model definition, return
} if (!this._isAttribute(key)) {
return;
}
// If attempting to set primary key and primary key is already defined, return // If attempting to set primary key and primary key is already defined, return
if (this.Model._hasPrimaryKeys && originalValue && this.Model._isPrimaryKey(key)) { if (this.Model._hasPrimaryKeys && originalValue && this.Model._isPrimaryKey(key)) {
return return
} }
// If attempting to set read only attributes, return // If attempting to set read only attributes, return
if (!options.raw && this.Model._hasReadOnlyAttributes && this.Model._isReadOnlyAttribute(key)) { if (this.Model._hasReadOnlyAttributes && this.Model._isReadOnlyAttribute(key)) {
return return
}
// Convert date fields to real date objects
if (this.Model._hasDateAttributes && this.Model._isDateAttribute(key) && value !== null && !(value instanceof Date)) {
value = new Date(value)
}
} }
// Convert boolean-ish values to booleans // Convert boolean-ish values to booleans
...@@ -194,12 +202,7 @@ module.exports = (function() { ...@@ -194,12 +202,7 @@ module.exports = (function() {
value = !!value value = !!value
} }
// Convert date fields to real date objects if (!options.raw && originalValue !== value) {
if (this.Model._hasDateAttributes && this.Model._isDateAttribute(key) && value !== null && !(value instanceof Date)) {
value = new Date(value)
}
if (originalValue !== value) {
this._previousDataValues[key] = originalValue this._previousDataValues[key] = originalValue
} }
this.dataValues[key] = value this.dataValues[key] = value
......
...@@ -350,37 +350,41 @@ module.exports = (function() { ...@@ -350,37 +350,41 @@ module.exports = (function() {
}) })
delete result.__children delete result.__children
}, },
primaryKeyAttribute primaryKeyAttribute,
primaryKeyMap = {}
// Identify singular primaryKey attribute for equality check (if possible)
if (includeOptions.daoFactory.primaryKeyAttributes.length === 1) {
primaryKeyAttribute = includeOptions.daoFactory.primaryKeyAttributes[0]
} else if (includeOptions.daoFactory.rawAttributes.id) {
primaryKeyAttribute = 'id'
}
// Ignore all include keys on main data // Ignore all include keys on main data
if (includeOptions.includeNames) { if (includeOptions.includeNames) {
calleeDataIgnore = calleeDataIgnore.concat(includeOptions.includeNames) calleeDataIgnore = calleeDataIgnore.concat(includeOptions.includeNames)
} }
if (includeOptions.daoFactory.primaryKeyAttributes.length === 1) {
primaryKeyAttribute = includeOptions.daoFactory.primaryKeyAttribute
}
data.forEach(function (row) { data.forEach(function parseRow(row) {
row = Dot.transform(row) row = Dot.transform(row)
calleeData = _.omit(row, calleeDataIgnore) calleeData = row
// If there are :M associations included we need to see if the main result of the row has already been identified // If there are :M associations included we need to see if the main result of the row has already been identified
existingResult = options.checkExisting && _.find(results, function (result) { if (options.checkExisting) {
// If we can, detect equality on the singular primary key
if (primaryKeyAttribute) { if (primaryKeyAttribute) {
return result[primaryKeyAttribute] === calleeData[primaryKeyAttribute] // If we can, detect equality on the singular primary key
existingResult = primaryKeyMap[calleeData[primaryKeyAttribute]]
} else {
// If we can't identify on a singular primary key, do a full row equality check
existingResult = _.find(results, function (result) {
return Utils._.isEqual(_.omit(result, calleeDataIgnore), calleeData)
})
} }
} else {
// If we can't identify on a singular primary key, do a full row equality check existingResult = null
return Utils._.isEqual(_.omit(result, calleeDataIgnore), calleeData) }
})
if (!existingResult) { if (!existingResult) {
results.push(existingResult = calleeData) results.push(existingResult = calleeData)
if (options.checkExisting && primaryKeyAttribute) {
primaryKeyMap[existingResult[primaryKeyAttribute]] = existingResult
}
} }
for (var attrName in row) { for (var attrName in row) {
...@@ -398,6 +402,9 @@ module.exports = (function() { ...@@ -398,6 +402,9 @@ module.exports = (function() {
} }
existingResult.__children[attrName].push(row[attrName]) existingResult.__children[attrName].push(row[attrName])
// Remove from main
delete existingResult[attrName]
} }
} }
} }
...@@ -406,6 +413,7 @@ module.exports = (function() { ...@@ -406,6 +413,7 @@ module.exports = (function() {
if (!options.checkExisting) { if (!options.checkExisting) {
parseChildren(existingResult) parseChildren(existingResult)
} }
}) })
// parseChildren after row parsing if duplicate values are possible // parseChildren after row parsing if duplicate values are possible
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
"lingo": "~0.0.5", "lingo": "~0.0.5",
"validator": "~3.2.0", "validator": "~3.2.0",
"moment": "~2.5.0", "moment": "~2.5.0",
"dottie": "0.2.0", "dottie": "0.2.1",
"toposort-class": "~0.3.0", "toposort-class": "~0.3.0",
"generic-pool": "2.0.4", "generic-pool": "2.0.4",
"sql": "~0.35.0", "sql": "~0.35.0",
......
...@@ -40,7 +40,7 @@ describe(Support.getTestDialectTeaser("Include"), function () { ...@@ -40,7 +40,7 @@ describe(Support.getTestDialectTeaser("Include"), function () {
it('should not throw an error when an empty include is named the same as the foreign key', function (done) { it('should not throw an error when an empty include is named the same as the foreign key', function (done) {
var section = this.sequelize.define('section', { name: DataTypes.STRING }); var section = this.sequelize.define('section', { name: DataTypes.STRING });
var layout = this.sequelize.define('layout', { name: DataTypes.STRING }); var layout = this.sequelize.define('layout', { name: DataTypes.STRING });
section.belongsTo(layout, { section.belongsTo(layout, {
as: layout.name, as: layout.name,
foreignKey: layout.name, foreignKey: layout.name,
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!