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

Commit 3780d3b7 by Mick Hansen

Merge pull request #1365 from overlookmotel/order-by-associations-refactor

Order by associations refactor
2 parents dc07afa3 8210ddef
...@@ -17,8 +17,10 @@ module.exports = (function() { ...@@ -17,8 +17,10 @@ module.exports = (function() {
this.options.foreignKey = Utils._.underscoredIf(Utils.singularize(this.source.tableName, this.source.options.language) + "Id", this.source.options.underscored) this.options.foreignKey = Utils._.underscoredIf(Utils.singularize(this.source.tableName, this.source.options.language) + "Id", this.source.options.underscored)
} }
if (!this.as) { if (this.as) {
this.as = this.options.as = Utils.singularize(this.target.tableName, this.target.options.language) this.isAliased = true
} else {
this.as = Utils.singularize(this.target.tableName, this.target.options.language)
} }
this.associationAccessor = this.isSelfAssociation this.associationAccessor = this.isSelfAssociation
......
...@@ -21,9 +21,10 @@ module.exports = (function() { ...@@ -21,9 +21,10 @@ module.exports = (function() {
this.isMultiAssociation = true this.isMultiAssociation = true
this.isSelfAssociation = this.source === this.target this.isSelfAssociation = this.source === this.target
this.doubleLinked = false this.doubleLinked = false
this.as = this.options.as
this.combinedTableName = Utils.combineTableNames( this.combinedTableName = Utils.combineTableNames(
this.source.tableName, this.source.tableName,
this.isSelfAssociation ? (this.options.as || this.target.tableName) : this.target.tableName this.isSelfAssociation ? (this.as || this.target.tableName) : this.target.tableName
) )
/* /*
...@@ -48,7 +49,7 @@ module.exports = (function() { ...@@ -48,7 +49,7 @@ module.exports = (function() {
* Determine associationAccessor, especially for include options to identify the correct model * Determine associationAccessor, especially for include options to identify the correct model
*/ */
this.associationAccessor = this.options.as this.associationAccessor = this.as
if (!this.associationAccessor && (typeof this.through === "string" || Object(this.through) === this.through)) { if (!this.associationAccessor && (typeof this.through === "string" || Object(this.through) === this.through)) {
this.associationAccessor = this.through.tableName || this.through this.associationAccessor = this.through.tableName || this.through
} }
...@@ -112,16 +113,20 @@ module.exports = (function() { ...@@ -112,16 +113,20 @@ module.exports = (function() {
this.options.tableName = this.combinedName = (this.through === Object(this.through) ? this.through.tableName : this.through) this.options.tableName = this.combinedName = (this.through === Object(this.through) ? this.through.tableName : this.through)
var as = (this.options.as || Utils.pluralize(this.target.tableName, this.target.options.language)) if (this.as) {
this.isAliased = true
} else {
this.as = Utils.pluralize(this.target.tableName, this.target.options.language)
}
this.accessors = { this.accessors = {
get: Utils._.camelize('get_' + as), get: Utils._.camelize('get_' + this.as),
set: Utils._.camelize('set_' + as), set: Utils._.camelize('set_' + this.as),
add: Utils._.camelize(Utils.singularize('add_' + as, this.target.options.language)), add: Utils._.camelize(Utils.singularize('add_' + this.as, this.target.options.language)),
create: Utils._.camelize(Utils.singularize('create_' + as, this.target.options.language)), create: Utils._.camelize(Utils.singularize('create_' + this.as, this.target.options.language)),
remove: Utils._.camelize(Utils.singularize('remove_' + as, this.target.options.language)), remove: Utils._.camelize(Utils.singularize('remove_' + this.as, this.target.options.language)),
hasSingle: Utils._.camelize(Utils.singularize('has_' + as, this.target.options.language)), hasSingle: Utils._.camelize(Utils.singularize('has_' + this.as, this.target.options.language)),
hasAll: Utils._.camelize('has_' + as) hasAll: Utils._.camelize('has_' + this.as)
} }
} }
......
...@@ -11,25 +11,28 @@ module.exports = (function() { ...@@ -11,25 +11,28 @@ module.exports = (function() {
this.options = options this.options = options
this.isSingleAssociation = true this.isSingleAssociation = true
this.isSelfAssociation = (this.source.tableName == this.target.tableName) this.isSelfAssociation = (this.source.tableName == this.target.tableName)
this.as = this.options.as
if (this.isSelfAssociation && !this.options.foreignKey && !!this.options.as) { if (this.isSelfAssociation && !this.options.foreignKey && !!this.as) {
this.options.foreignKey = Utils._.underscoredIf(Utils.singularize(this.options.as, this.target.options.language) + "Id", this.options.underscored) this.options.foreignKey = Utils._.underscoredIf(Utils.singularize(this.as, this.target.options.language) + "Id", this.options.underscored)
} }
if (!this.options.as) { if (this.as) {
this.options.as = Utils.singularize(this.target.tableName, this.target.options.language) this.isAliased = true
} else {
this.as = Utils.singularize(this.target.tableName, this.target.options.language)
} }
this.associationAccessor = this.isSelfAssociation this.associationAccessor = this.isSelfAssociation
? Utils.combineTableNames(this.target.tableName, this.options.as) ? Utils.combineTableNames(this.target.tableName, this.as)
: this.options.as : this.as
this.options.useHooks = options.useHooks this.options.useHooks = options.useHooks
this.accessors = { this.accessors = {
get: Utils._.camelize('get_' + this.options.as), get: Utils._.camelize('get_' + this.as),
set: Utils._.camelize('set_' + this.options.as), set: Utils._.camelize('set_' + this.as),
create: Utils._.camelize('create_' + this.options.as) create: Utils._.camelize('create_' + this.as)
} }
} }
......
...@@ -59,36 +59,32 @@ Mixin.hasMany = function(associatedDAOFactory, options) { ...@@ -59,36 +59,32 @@ Mixin.hasMany = function(associatedDAOFactory, options) {
return this return this
} }
Mixin.getAssociation = function(target) { Mixin.getAssociation = function(target, alias) {
var result = null
for (var associationName in this.associations) { for (var associationName in this.associations) {
if (this.associations.hasOwnProperty(associationName)) { if (this.associations.hasOwnProperty(associationName)) {
var association = this.associations[associationName] var association = this.associations[associationName]
if (!result && (association.target === target)) { if (association.target === target && (alias === undefined ? !association.isAliased : association.as === alias)) {
result = association return association
} }
} }
} }
return result return null
} }
Mixin.getAssociationByAlias = function(alias) { Mixin.getAssociationByAlias = function(alias) {
var result = null
for (var associationName in this.associations) { for (var associationName in this.associations) {
if (this.associations.hasOwnProperty(associationName)) { if (this.associations.hasOwnProperty(associationName)) {
var association = this.associations[associationName] var association = this.associations[associationName]
if (!result && (association.options.as === alias)) { if (association.as === alias) {
result = association return association
} }
} }
} }
return result return null
} }
/* example for instance methods: /* example for instance methods:
......
...@@ -1349,100 +1349,85 @@ module.exports = (function() { ...@@ -1349,100 +1349,85 @@ module.exports = (function() {
var validateIncludedElement = function(include, parent) { var validateIncludedElement = function(include, parent) {
if (include instanceof DAOFactory) { if (include instanceof DAOFactory) {
include = { daoFactory: include, as: include.tableName } include = { daoFactory: include }
} }
if (typeof parent === "undefined") { if (typeof parent === "undefined") {
parent = this parent = this
} }
if (typeof include === 'object') { if (typeof include !== 'object') {
if (include.hasOwnProperty('model')) { throw new Error('Include unexpected. Element has to be either an instance of DAOFactory or an object.')
include.daoFactory = include.model }
delete include.model
}
if (!include.hasOwnProperty('as')) { if (include.hasOwnProperty('model')) {
include.as = include.daoFactory.tableName include.daoFactory = include.model
} delete include.model
} else if (!include.hasOwnProperty('daoFactory')) {
throw new Error('Include malformed. Expected attributes: daoFactory, as!')
}
if (include.hasOwnProperty('attributes')) { if (include.hasOwnProperty('attributes')) {
var primaryKeys; var primaryKeys;
if (include.daoFactory.hasPrimaryKeys) { if (include.daoFactory.hasPrimaryKeys) {
primaryKeys = [] primaryKeys = []
for (var field_name in include.daoFactory.primaryKeys) { for (var field_name in include.daoFactory.primaryKeys) {
primaryKeys.push(field_name) primaryKeys.push(field_name)
}
} else {
primaryKeys = ['id']
} }
include.attributes = include.attributes.concat(primaryKeys)
} else { } else {
include.attributes = Object.keys(include.daoFactory.attributes) primaryKeys = ['id']
} }
include.attributes = include.attributes.concat(primaryKeys)
} else {
include.attributes = Object.keys(include.daoFactory.attributes)
}
// pseudo include just needed the attribute logic, return // pseudo include just needed the attribute logic, return
if (include._pseudo) return include if (include._pseudo) return include
if (include.hasOwnProperty('daoFactory') && (include.hasOwnProperty('as'))) { // check if the current daoFactory is actually associated with the passed daoFactory - or it's a pseudo include
var usesAlias = (include.as !== include.daoFactory.tableName) var association = parent.getAssociation(include.daoFactory, include.as)
, association = (usesAlias ? parent.getAssociationByAlias(include.as) : parent.getAssociation(include.daoFactory)) if (association) {
include.association = association
// If single (1:1) association, we singularize the alias, so it will match the automatically generated alias of belongsTo/HasOne include.as = association.as
if (association && !usesAlias && association.isSingleAssociation) {
include.as = Utils.singularize(include.daoFactory.tableName, include.daoFactory.options.language) // If through, we create a pseudo child include, to ease our parsing later on
if (Object(include.association.through) === include.association.through) {
if (!include.include) include.include = []
var through = include.association.through
include.through = {
daoFactory: through,
as: Utils.singularize(through.tableName, through.options.language),
association: {
isSingleAssociation: true
},
_pseudo: true
} }
// check if the current daoFactory is actually associated with the passed daoFactory - or it's a pseudo include include.include.push(include.through)
if (association && (!association.options.as || (association.options.as === include.as))) { }
include.association = association
// If through, we create a pseudo child include, to ease our parsing later on
if (Object(include.association.through) === include.association.through) {
if (!include.include) include.include = []
var through = include.association.through
include.through = {
daoFactory: through,
as: Utils.singularize(through.tableName, through.options.language),
association: {
isSingleAssociation: true
},
_pseudo: true
}
include.include.push(include.through)
}
if (include.required === undefined) { if (include.required === undefined) {
include.required = false include.required = !!include.where
if (include.where) { }
include.required = true
}
}
// Validate child includes // Validate child includes
if (include.hasOwnProperty('include')) { if (include.hasOwnProperty('include')) {
validateIncludedElements(include) validateIncludedElements(include)
} }
return include return include
} else { } else {
var msg = include.daoFactory.name var msg = include.daoFactory.name
if (usesAlias) { if (include.as) {
msg += " (" + include.as + ")" msg += " (" + include.as + ")"
} }
msg += " is not associated to " + this.name + "!" msg += " is not associated to " + this.name + "!"
throw new Error(msg) throw new Error(msg)
}
} else {
throw new Error('Include malformed. Expected attributes: daoFactory, as!')
}
} else {
throw new Error('Include unexpected. Element has to be either an instance of DAOFactory or an object.')
} }
} }
......
...@@ -356,58 +356,44 @@ module.exports = (function() { ...@@ -356,58 +356,44 @@ module.exports = (function() {
} else if (Array.isArray(obj)) { } else if (Array.isArray(obj)) {
// loop through array, adding table names of models to quoted // loop through array, adding table names of models to quoted
// (checking associations to see if names should be singularised or not) // (checking associations to see if names should be singularised or not)
var quoted = [] var tableNames = []
, i , parentAssociation
, len = obj.length , len = obj.length
for (i = 0; i < len - 1; i++) { for (var i = 0; i < len - 1; i++) {
var item = obj[i] var item = obj[i]
if (Utils._.isString(item) || item instanceof Utils.fn || item instanceof Utils.col || item instanceof Utils.literal || item instanceof Utils.cast || 'raw' in item) { if (Utils._.isString(item) || item instanceof Utils.fn || item instanceof Utils.col || item instanceof Utils.literal || item instanceof Utils.cast || 'raw' in item) {
break break
} }
var model, as
if (item instanceof daoFactory) { if (item instanceof daoFactory) {
item = {model: item} model = item
} else {
model = item.model
as = item.as
} }
// find applicable association for linking parent to this model // check if model provided is through table
var model = item.model var association
, as if (!as && parentAssociation && parentAssociation.through === model) {
, associations = parent.associations association = {as: Utils.singularize(model.tableName, model.options.language)}
, association
if (item.hasOwnProperty('as')) {
as = item.as
association = Utils._.find(associations, function(association, associationName) {
return association.target === model && associationName === as
})
} else { } else {
association = Utils._.find(associations, function(association, associationName) { // find applicable association for linking parent to this model
return association.target === model ? association = parent.getAssociation(model, as)
associationName === (
association.doubleLinked ?
association.combinedName:
(
association.isSingleAssociation ?
Utils.singularize(model.tableName, model.options.language) :
parent.tableName + model.tableName
)
) :
association.targetAssociation && association.targetAssociation.through === model
})
// NB association.target !== model clause below is to singularize names of through tables in hasMany-hasMany joins
as = (association && (association.isSingleAssociation || association.target !== model)) ? Utils.singularize(model.tableName, model.options.language) : model.tableName
} }
quoted[i] = as if (association) {
tableNames[i] = association.as
if (!association) { parent = model
throw new Error('\'' + quoted.join('.') + '\' in order / group clause is not valid association') parentAssociation = association
} else {
tableNames[i] = model.tableName
throw new Error('\'' + tableNames.join('.') + '\' in order / group clause is not valid association')
} }
parent = model
} }
// add 1st string as quoted, 2nd as unquoted raw // add 1st string as quoted, 2nd as unquoted raw
var sql = (i > 0 ? this.quoteIdentifier(quoted.join('.')) + '.' : '') + this.quote(obj[i], parent, force) var sql = (i > 0 ? this.quoteIdentifier(tableNames.join('.')) + '.' : '') + this.quote(obj[i], parent, force)
if (i < len - 1) { if (i < len - 1) {
sql += ' ' + obj[i + 1] sql += ' ' + obj[i + 1]
} }
......
...@@ -511,7 +511,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -511,7 +511,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
'user_id', 'user_id',
'message' 'message'
], ],
include: [{ model: User, as: User.tableName, attributes: ['username'] }] include: [{ model: User, attributes: ['username'] }]
}).success(function(messages) { }).success(function(messages) {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!