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

Commit f798e806 by Sascha Depold

association prefetching is now also working with aliased associations

1 parent 27f89487
......@@ -24,7 +24,7 @@ Mixin.belongsTo = function(associatedDAO, options) {
association.injectGetter(this.DAO.prototype);
association.injectSetter(this.DAO.prototype);
return this
}
......@@ -32,21 +32,39 @@ Mixin.hasMany = function(associatedDAO, options) {
// the id is in the foreign table or in a connecting table
var association = new HasMany(this, associatedDAO, Utils._.extend((options||{}), this.options))
this.associations[association.associationAccessor] = association.injectAttributes()
association.injectGetter(this.DAO.prototype);
association.injectSetter(this.DAO.prototype);
return this
}
Mixin.getAssociation = function(target, options) {
Mixin.getAssociation = function(target) {
var result = null
for (var associationName in this.associations) {
if (this.associations.hasOwnProperty(associationName)) {
var association = this.associations[associationName]
if (!result && (association.target === target)) {
result = association
}
}
}
return result
}
Mixin.getAssociationByAlias = function(alias) {
var result = null
for (var associationName in this.associations) {
var association = this.associations[associationName]
if (this.associations.hasOwnProperty(associationName)) {
var association = this.associations[associationName]
if (!result && (association.target === target)) {
result = association
if (!result && (association.options.as === alias)) {
result = association
}
}
}
......
......@@ -69,9 +69,9 @@ module.exports = (function() {
this.DAO.prototype.rawAttributes = this.rawAttributes;
if (this.options.instanceMethods) {
Utils._.each(this.options.instanceMethods, function(fct, name) {
self.DAO.prototype[name] = fct
})
Utils._.each(this.options.instanceMethods, function(fct, name) {
self.DAO.prototype[name] = fct
})
}
this.DAO.prototype.attributes = Object.keys(this.DAO.prototype.rawAttributes);
......@@ -196,6 +196,10 @@ module.exports = (function() {
includes.forEach(function(daoName) {
options.include[daoName] = this.daoFactoryManager.getDAO(daoName)
if (!options.include[daoName]) {
options.include[daoName] = this.getAssociationByAlias(daoName).target
}
}.bind(this))
}
......
......@@ -133,14 +133,33 @@ module.exports = (function() {
// private //
/////////////
/**
* Iterate over all known tables and search their names inside the sql query.
* This method will also check association aliases ('as' option).
*
* @param {String} attribute An attribute of a SQL query. (?)
* @return {String} The found tableName / alias.
*/
var findTableNameInAttribute = function(attribute) {
var tableName = null
this.sequelize.daoFactoryManager.daos.forEach(function(daoFactory) {
if (!!tableName) {
return
} else if (attribute.indexOf(daoFactory.tableName + ".") === 0) {
tableName = daoFactory.tableName
} else if (attribute.indexOf(Utils.singularize(daoFactory.tableName) + ".") === 0) {
tableName = Utils.singularize(daoFactory.tableName)
} else {
if (attribute.indexOf(daoFactory.tableName+".") === 0) tableName = daoFactory.tableName;
for (var associationName in daoFactory.associations) {
if (daoFactory.associations.hasOwnProperty(associationName)) {
var association = daoFactory.associations[associationName]
if (attribute.indexOf(association.options.as + ".") === 0) {
tableName = association.options.as
}
}
}
}
})
......@@ -242,15 +261,29 @@ module.exports = (function() {
}
var buildAssociatedDaoInstances = function(tableName, associationData, dao) {
var associatedDao = this.sequelize.daoFactoryManager.getDAO(tableName, { attribute: 'tableName' })
, association = this.callee.getAssociation(associatedDao)
, accessor = Utils._.camelize(associatedDao.tableName)
var associatedDaoFactory = this.sequelize.daoFactoryManager.getDAO(tableName, { attribute: 'tableName' })
, association = null
if (!!associatedDaoFactory) {
association = this.callee.getAssociation(associatedDaoFactory)
} else {
associatedDaoFactory = this.sequelize.daoFactoryManager.getDAO(Utils.pluralize(tableName), { attribute: 'tableName' })
if (!!associatedDaoFactory) {
association = this.callee.getAssociation(associatedDaoFactory)
} else {
association = this.callee.getAssociationByAlias(tableName)
associatedDaoFactory = association.target
}
}
var accessor = Utils._.camelize(tableName)
// downcase the first char
accessor = accessor.slice(0,1).toLowerCase() + accessor.slice(1)
associationData.forEach(function(data) {
var daoInstance = associatedDao.build(data, { isNewRecord: false })
var daoInstance = associatedDaoFactory.build(data, { isNewRecord: false })
if (['BelongsTo', 'HasOne'].indexOf(association.associationType) > -1) {
accessor = Utils.singularize(accessor)
......
......@@ -161,10 +161,15 @@ module.exports = (function() {
query += Utils.addTicks(association.associationType === 'BelongsTo' ? tableName : dao.tableName) + '.' + Utils.addTicks('id')
}
var aliasAssoc = daoFactory.getAssociationByAlias(daoName)
, aliasName = !!aliasAssoc ? Utils.addTicks(daoName) : _tableName
optAttributes = optAttributes.concat(
Utils._.keys(dao.attributes).map(function(attr) {
var identifier = [_tableName, Utils.addTicks(attr)]
return identifier.join('.') + ' AS ' + Utils.addTicks(identifier.join('.'))
return '' +
[_tableName, Utils.addTicks(attr)].join('.') +
' AS ' +
Utils.addTicks([aliasName, attr].join('.'))
})
)
}
......
......@@ -236,10 +236,15 @@ module.exports = (function() {
query += addQuotes(association.associationType === 'BelongsTo' ? tableName : dao.tableName) + '.' + addQuotes('id')
}
var aliasAssoc = daoFactory.getAssociationByAlias(daoName)
, aliasName = !!aliasAssoc ? addQuotes(daoName) : _tableName
optAttributes = optAttributes.concat(
Utils._.keys(dao.attributes).map(function(attr) {
var identifier = [_tableName, addQuotes(attr)]
return identifier.join('.') + ' AS "' + removeQuotes(identifier.join('.')) + '"'
return '' +
[_tableName, addQuotes(attr)].join('.') +
' AS "' +
removeQuotes([aliasName, attr].join('.')) + '"'
})
)
}
......
......@@ -450,52 +450,80 @@ describe("[" + Helpers.getTestDialectTeaser() + "] DAOFactory", function() {
})
})
it('fetches associated objects for 1:1 associations (1st direction)', function(done) {
this.User.hasOne(this.Task)
this.Task.belongsTo(this.User)
describe('1:1 associations', function() {
it('fetches associated objects (1st direction)', function(done) {
this.User.hasOne(this.Task)
this.Task.belongsTo(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
this.User.find({
where: { 'UserWithNames.id': 1 },
include: [ 'Task' ]
}).success(function(user) {
expect(user.task).toBeDefined()
expect(user.task.id).toEqual(task.id)
done()
})
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
})
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
this.User.find({
where: { 'UserWithNames.id': 1 },
include: [ 'Task' ]
}).success(function(user) {
expect(user.task).toBeDefined()
expect(user.task.id).toEqual(task.id)
done()
})
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
})
it('fetches associated objects for 1:1 associations (2nd direction)', function(done) {
this.User.hasOne(this.Task)
this.Task.belongsTo(this.User)
it('fetches associated objects via "as" param (1st direction)', function(done) {
this.User.hasOne(this.Task, { as: 'Homework' })
this.Task.belongsTo(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.User.create({ name: 'another user' }).success(function(another_user) {
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
this.Task.find({
where: { 'Tasks.id': 1 },
include: [ 'UserWithName' ]
}).success(function(task) {
expect(task.userWithName).toBeDefined()
expect(task.userWithName.id).toEqual(user.id)
user.setHomework(task).success(function() {
this.User.find({
where: { 'UserWithNames.id': 1 },
include: [ 'Homework' ]
}).success(function(user) {
expect(user.homework).toBeDefined()
expect(user.homework.id).toEqual(task.id)
done()
})
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}.bind(this)) //- sequelize.sync
})
it('fetches associated object (2nd direction)', function(done) {
this.User.hasOne(this.Task)
this.Task.belongsTo(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.User.create({ name: 'another user' }).success(function(another_user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
this.Task.find({
where: { 'Tasks.id': 1 },
include: [ 'UserWithName' ]
}).success(function(task) {
expect(task.userWithName).toBeDefined()
expect(task.userWithName.id).toEqual(user.id)
done()
})
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
})
})
it('fetches associated objects for 1:N associations (1st direction)', function(done) {
this.User.hasMany(this.Task)
this.Task.belongsTo(this.User)
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!