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

Commit c7592d70 by Sascha Depold

added method for fetching associated data

1 parent f5c504a6
...@@ -14,6 +14,10 @@ exports.Helper = function(Sequelize) { ...@@ -14,6 +14,10 @@ exports.Helper = function(Sequelize) {
}, },
SQL: { SQL: {
isManyToManyAssociation: function(association) {
return (['hasMany', 'hasAndBelongsToMany'].indexOf(association.type) > -1)
},
manyToManyTableName: function(name1, name2) { manyToManyTableName: function(name1, name2) {
var _name1 = name1[0].toUpperCase() + name1.replace(/^./, "") var _name1 = name1[0].toUpperCase() + name1.replace(/^./, "")
var _name2 = name2[0].toUpperCase() + name2.replace(/^./, "") var _name2 = name2[0].toUpperCase() + name2.replace(/^./, "")
......
...@@ -9,11 +9,11 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -9,11 +9,11 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
options = options || {} options = options || {}
options.classMethods = options.classMethods || {} options.classMethods = options.classMethods || {}
options.instanceMethods = options.instanceMethods || {} options.instanceMethods = options.instanceMethods || {}
var table = function(values) { var table = function(values) {
var self = this, var self = this,
defaults = {} defaults = {}
// read all default values ... // read all default values ...
Sequelize.Helper.Hash.forEach(table.attributes, function(options, key) { Sequelize.Helper.Hash.forEach(table.attributes, function(options, key) {
if(typeof options.default != 'undefined') defaults[key] = options.default if(typeof options.default != 'undefined') defaults[key] = options.default
...@@ -21,7 +21,7 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -21,7 +21,7 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
// and merge them into the passed one // and merge them into the passed one
Sequelize.Helper.Hash.merge(defaults, values) Sequelize.Helper.Hash.merge(defaults, values)
// now iterate over the values and assign them the current object // now iterate over the values and assign them the current object
Sequelize.Helper.Hash.forEach(values, function(value, key) { Sequelize.Helper.Hash.forEach(values, function(value, key) {
if(attributes[key]) { if(attributes[key]) {
...@@ -33,17 +33,17 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -33,17 +33,17 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
self[key] = value self[key] = value
} }
}) })
this.id = null // specify id as null to declare this object as unsaved and as not present in the database this.id = null // specify id as null to declare this object as unsaved and as not present in the database
this.table = table this.table = table
} }
// class methods // class methods
var classMethods = { var classMethods = {
associations: [], associations: [],
attributes: attributes, attributes: attributes,
tableName: tableName, tableName: tableName,
prepareAssociations: function(callback) { prepareAssociations: function(callback) {
table.associations.forEach(function(association) { table.associations.forEach(function(association) {
var assocNameAsTableIdentifier = Sequelize.Helper.SQL.asTableIdentifier(association.name) var assocNameAsTableIdentifier = Sequelize.Helper.SQL.asTableIdentifier(association.name)
...@@ -81,7 +81,7 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -81,7 +81,7 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
}) })
if(callback) callback() if(callback) callback()
}, },
/* returns: table, error */ /* returns: table, error */
sync: function(callback) { sync: function(callback) {
var fields = ["id INT NOT NULL auto_increment PRIMARY KEY"] var fields = ["id INT NOT NULL auto_increment PRIMARY KEY"]
...@@ -139,33 +139,33 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -139,33 +139,33 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
object.id = result.id object.id = result.id
return object return object
}, },
hasAndBelongsToMany: function(assocName) { hasAndBelongsToMany: function(assocName) {
if(typeof assocName == 'undefined') if(typeof assocName == 'undefined')
throw new Error('Please specify at least an association name!') throw new Error('Please specify at least an association name!')
var association = { name: assocName, table: table, type: 'hasAndBelongsToMany' }, var association = { name: assocName, table: table, type: 'hasAndBelongsToMany' },
Factory = new require("./Factory").Factory(Sequelize, sequelize) Factory = new require("./Factory").Factory(Sequelize, sequelize)
table.associations.push(association) table.associations.push(association)
table.prototype[Sequelize.Helper.SQL.addPrefix('get', assocName)] = Factory.createManyToManyGetter(null, table, assocName, table.tableName) table.prototype[Sequelize.Helper.SQL.addPrefix('get', assocName)] = Factory.createManyToManyGetter(null, table, assocName, table.tableName)
table.prototype[Sequelize.Helper.SQL.addPrefix('set', assocName)] = Factory.createManyToManySetter(table, table, assocName, table.tableName) table.prototype[Sequelize.Helper.SQL.addPrefix('set', assocName)] = Factory.createManyToManySetter(table, table, assocName, table.tableName)
return association return association
}, },
hasMany: function(assocName, associationTable, backAssocName) { hasMany: function(assocName, associationTable, backAssocName) {
if(typeof assocName == 'undefined') if(typeof assocName == 'undefined')
throw new Error('Please specify at least an association name!') throw new Error('Please specify at least an association name!')
if(associationTable) { if(associationTable) {
var Factory = new require("./Factory").Factory(Sequelize, sequelize), var Factory = new require("./Factory").Factory(Sequelize, sequelize),
association = { name: assocName, backAssociationName: backAssocName, table: associationTable, type: 'hasMany' }, association = { name: assocName, backAssociationName: backAssocName, table: associationTable, type: 'hasMany' },
backAssociation = { name: backAssocName, backAssociationName: assocName, table: table, type: 'hasMany' } backAssociation = { name: backAssocName, backAssociationName: assocName, table: table, type: 'hasMany' }
table.associations.push(association) table.associations.push(association)
if(backAssocName) { if(backAssocName) {
associationTable.associations.push(backAssociation) associationTable.associations.push(backAssociation)
Factory.addManyToManyMethods(table, associationTable, assocName, backAssocName) Factory.addManyToManyMethods(table, associationTable, assocName, backAssocName)
...@@ -173,37 +173,37 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -173,37 +173,37 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
} else { } else {
Factory.addOneToManyMethods(table, associationTable, assocName) Factory.addOneToManyMethods(table, associationTable, assocName)
} }
return association return association
} else { } else {
return this.hasAndBelongsToMany(assocName) return this.hasAndBelongsToMany(assocName)
} }
}, },
hasManyAndBelongsTo: function(assocName, _table, backAssocName) { hasManyAndBelongsTo: function(assocName, _table, backAssocName) {
var assoc = table.hasMany(assocName, _table) var assoc = table.hasMany(assocName, _table)
_table.belongsTo(backAssocName || assocName, table, assoc) _table.belongsTo(backAssocName || assocName, table, assoc)
}, },
hasOne: function(assocName, _table) { hasOne: function(assocName, _table) {
var Factory = new require("./Factory").Factory(Sequelize, sequelize), var Factory = new require("./Factory").Factory(Sequelize, sequelize),
association = { name: assocName, table: _table, type: 'hasOne' } association = { name: assocName, table: _table, type: 'hasOne' }
table.associations.push(association) table.associations.push(association)
Factory.addOneToOneMethods(table, _table, assocName) Factory.addOneToOneMethods(table, _table, assocName)
return association return association
}, },
hasOneAndBelongsTo: function(assocName, _table, backAssocName) { hasOneAndBelongsTo: function(assocName, _table, backAssocName) {
var assoc = table.hasOne(assocName, _table) var assoc = table.hasOne(assocName, _table)
_table.belongsTo(backAssocName || assocName, table, assoc) _table.belongsTo(backAssocName || assocName, table, assoc)
}, },
belongsTo: function(assocName, _table, backAssociation) { belongsTo: function(assocName, _table, backAssociation) {
if(typeof backAssociation == 'undefined') if(typeof backAssociation == 'undefined')
throw new Error("Calling belongsTo with only two parameters is deprecated! Please take a look at the example in the repository!") throw new Error("Calling belongsTo with only two parameters is deprecated! Please take a look at the example in the repository!")
// start - overwrite the association of the before defined hasOne or hasMany relation, to fit the belongsTo foreign keys // start - overwrite the association of the before defined hasOne or hasMany relation, to fit the belongsTo foreign keys
var Factory = new require("./Factory").Factory(Sequelize, sequelize) var Factory = new require("./Factory").Factory(Sequelize, sequelize)
...@@ -216,12 +216,13 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -216,12 +216,13 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
delete _table.prototype[Sequelize.Helper.SQL.addPrefix('set', backAssociation.name)] delete _table.prototype[Sequelize.Helper.SQL.addPrefix('set', backAssociation.name)]
Factory.addOneToOneMethods(_table, table, assocName, backAssociation.name) Factory.addOneToOneMethods(_table, table, assocName, backAssociation.name)
} }
backAssociation.name = assocName // TODO: check if the following line is not needed; specs r failing
// backAssociation.name = assocName
// end - overwrite the association of the before defined hasOne or hasMany relation, to fit the belongsTo foreign keys // end - overwrite the association of the before defined hasOne or hasMany relation, to fit the belongsTo foreign keys
table.associations.push({ name: assocName, table: _table, type: 'belongsTo' }) table.associations.push({ name: assocName, table: _table, type: 'belongsTo' })
// getter // getter
table.prototype[Sequelize.Helper.SQL.addPrefix('get', assocName, true)] = function(callback) { table.prototype[Sequelize.Helper.SQL.addPrefix('get', assocName, true)] = function(callback) {
var identifier = Sequelize.Helper.SQL.asTableIdentifier(assocName) var identifier = Sequelize.Helper.SQL.asTableIdentifier(assocName)
...@@ -229,25 +230,25 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -229,25 +230,25 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
if((this[identifier] == null)||(isNaN(this[identifier]))) callback([]) if((this[identifier] == null)||(isNaN(this[identifier]))) callback([])
else _table.find(this[identifier], callback) else _table.find(this[identifier], callback)
} }
// setter // setter
table.prototype[Sequelize.Helper.SQL.addPrefix('set', assocName, true)] = function(object, callback) { table.prototype[Sequelize.Helper.SQL.addPrefix('set', assocName, true)] = function(object, callback) {
var self = this, var self = this,
attr = {} attr = {}
attr[Sequelize.Helper.SQL.asTableIdentifier(assocName)] = object.id attr[Sequelize.Helper.SQL.asTableIdentifier(assocName)] = object.id
this.updateAttributes(attr, function() { this.updateAttributes(attr, function() {
self[Sequelize.Helper.SQL.addPrefix('get', assocName, true)](callback) self[Sequelize.Helper.SQL.addPrefix('get', assocName, true)](callback)
}) })
} }
return _table return _table
} }
} }
// don't put this into the hash! // don't put this into the hash!
classMethods.identifier = Sequelize.Helper.SQL.asTableIdentifier(classMethods.tableName) classMethods.identifier = Sequelize.Helper.SQL.asTableIdentifier(classMethods.tableName)
// instance methods // instance methods
table.prototype = { table.prototype = {
get values() { get values() {
...@@ -260,32 +261,55 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -260,32 +261,55 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
return result return result
}, },
get invalidFields() { get invalidFields() {
var result = [], var result = [],
self = this self = this
Sequelize.Helper.Hash.forEach(table.attributes, function(options, attribute) { Sequelize.Helper.Hash.forEach(table.attributes, function(options, attribute) {
if(['createdAt', 'updatedAt'].indexOf(attribute) > -1) return if(['createdAt', 'updatedAt'].indexOf(attribute) > -1) return
var allowsNull = ((typeof options.allowNull == 'undefined') || (options.allowNull !== false)) var allowsNull = ((typeof options.allowNull == 'undefined') || (options.allowNull !== false))
var hasDefault = (typeof options.default != 'undefined') var hasDefault = (typeof options.default != 'undefined')
if(!allowsNull && !hasDefault && (typeof self[attribute] == 'undefined')) if(!allowsNull && !hasDefault && (typeof self[attribute] == 'undefined'))
result.push({ field: attribute, reason: 'The field does not allow NULL values and has no default!'}) result.push({ field: attribute, reason: 'The field does not allow NULL values and has no default!'})
}) })
return result return result
}, },
get isValid() { get isValid() {
return this.invalidFields.length == 0 return this.invalidFields.length == 0
}, },
get isNewRecord() { get isNewRecord() {
return this.id == null return this.id == null
}, },
loadAssociatedData: function(callback) {
var associatedData = {},
self = this,
setAssociatedDataAndReturn = function() {
self.associatedData = associatedData
if(callback) callback(associatedData)
}
if(this.table.associations.length == 0)
setAssociatedDataAndReturn()
else
this.table.associations.forEach(function(association) {
var isManyToManyAssociation = Sequelize.Helper.SQL.isManyToManyAssociation(association),
getter = Sequelize.Helper.SQL.addPrefix('get', association.name, !isManyToManyAssociation)
self[getter](function(objects) {
associatedData[association.name] = objects
if(Sequelize.Helper.Hash.keys(associatedData).length == self.table.associations.length)
setAssociatedDataAndReturn()
})
})
},
save: function(callback) { save: function(callback) {
var query = null, var query = null,
self = this self = this
...@@ -298,7 +322,7 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -298,7 +322,7 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
this.updatedAt = new Date() this.updatedAt = new Date()
if(this.isNewRecord) { if(this.isNewRecord) {
this.createdAt = new Date() this.createdAt = new Date()
query = Sequelize.sqlQueryFor('insert', { query = Sequelize.sqlQueryFor('insert', {
table: table.tableName, table: table.tableName,
fields: Sequelize.Helper.SQL.fieldsForInsertQuery(this), fields: Sequelize.Helper.SQL.fieldsForInsertQuery(this),
...@@ -307,13 +331,13 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -307,13 +331,13 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
} else { } else {
query = Sequelize.sqlQueryFor('update', { table: table.tableName, values: Sequelize.Helper.SQL.valuesForUpdate(this), id: this.id }) query = Sequelize.sqlQueryFor('update', { table: table.tableName, values: Sequelize.Helper.SQL.valuesForUpdate(this), id: this.id })
} }
sequelize.query(query, function(result, stats) { sequelize.query(query, function(result, stats) {
self.id = self.id || stats.insert_id self.id = self.id || stats.insert_id
if(callback) callback(self) if(callback) callback(self)
}) })
}, },
updateAttributes: function(newValues, callback) { updateAttributes: function(newValues, callback) {
var self = this var self = this
Sequelize.Helper.Hash.keys(table.attributes).forEach(function(attribute) { Sequelize.Helper.Hash.keys(table.attributes).forEach(function(attribute) {
...@@ -323,7 +347,7 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -323,7 +347,7 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
this.save(callback) this.save(callback)
}, },
destroy: function(callback) { destroy: function(callback) {
sequelize.query( sequelize.query(
Sequelize.sqlQueryFor('delete', { table: table.tableName, where: ['id', this.id].join("=") }), Sequelize.sqlQueryFor('delete', { table: table.tableName, where: ['id', this.id].join("=") }),
...@@ -331,17 +355,17 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o ...@@ -331,17 +355,17 @@ exports.SequelizeTable = function(Sequelize, sequelize, tableName, attributes, o
) )
} }
} }
// merge classMethods + passed classMethods // merge classMethods + passed classMethods
Sequelize.Helper.Hash.merge(options.classMethods, classMethods) Sequelize.Helper.Hash.merge(options.classMethods, classMethods)
Sequelize.Helper.Hash.forEach(classMethods, function(method, methodName) { Sequelize.Helper.Hash.forEach(classMethods, function(method, methodName) {
table[methodName] = method table[methodName] = method
}) })
// merge passed instanceMethods // merge passed instanceMethods
Sequelize.Helper.Hash.forEach(options.instanceMethods, function(method, methodName) { Sequelize.Helper.Hash.forEach(options.instanceMethods, function(method, methodName) {
table.prototype[methodName] = method table.prototype[methodName] = method
}) })
return table return table
} }
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!