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

Commit f96f2f6b by Mick Hansen

Merge pull request #1547 from sequelize/schema-includes

Get includes working with schemas
2 parents c7d40186 ccef1508
...@@ -9,6 +9,7 @@ Notice: All 1.7.x changes are present in 2.0.x aswell ...@@ -9,6 +9,7 @@ Notice: All 1.7.x changes are present in 2.0.x aswell
- [BUG] Fixed a bug with foreign keys pointing to attributes that were not integers. Now your primaryKey can be a string, and associations will still work. Thanks to @fixe [#1544](https://github.com/sequelize/sequelize/pull/1544) - [BUG] Fixed a bug with foreign keys pointing to attributes that were not integers. Now your primaryKey can be a string, and associations will still work. Thanks to @fixe [#1544](https://github.com/sequelize/sequelize/pull/1544)
- [BUG] Fix a case where createdAt timestamp would not be set when updatedAt was disabled Thanks to @fixe [#1543](https://github.com/sequelize/sequelize/pull/1543) - [BUG] Fix a case where createdAt timestamp would not be set when updatedAt was disabled Thanks to @fixe [#1543](https://github.com/sequelize/sequelize/pull/1543)
- [BUG] Fix a case where timestamps were not being write protected in `set` when underscored=true. janmeier [#1523](https://github.com/sequelize/sequelize/pull/1523) - [BUG] Fix a case where timestamps were not being write protected in `set` when underscored=true. janmeier [#1523](https://github.com/sequelize/sequelize/pull/1523)
- [FEATURE/BUG] Prefetching/includes now fully support schemas
#### Backwards compatability changes #### Backwards compatability changes
...@@ -21,6 +22,7 @@ Notice: All 1.7.x changes are present in 2.0.x aswell ...@@ -21,6 +22,7 @@ Notice: All 1.7.x changes are present in 2.0.x aswell
- if you have non-id primary keys you should go through your associations and set the foreignKey option if relying on a incorrect _id foreign key - if you have non-id primary keys you should go through your associations and set the foreignKey option if relying on a incorrect _id foreign key
- syncOnAssocation has been removed. It only worked for n:m, and having a synchronous function (hasMany) that invokes an asynchronous function (sync) without returning an emitter does not make a lot of sense. If you (implicitly) depended on this feature, sequelize.sync is your friend. If you do not want to do a full sync, use custom through models for n:m (`M1.hasMany(M2, { through: M3})`) and sync the through model explicitly. - syncOnAssocation has been removed. It only worked for n:m, and having a synchronous function (hasMany) that invokes an asynchronous function (sync) without returning an emitter does not make a lot of sense. If you (implicitly) depended on this feature, sequelize.sync is your friend. If you do not want to do a full sync, use custom through models for n:m (`M1.hasMany(M2, { through: M3})`) and sync the through model explicitly.
- Join tables will be no longer be paranoid (have a deletedAt timestamp added), even though other models are. - Join tables will be no longer be paranoid (have a deletedAt timestamp added), even though other models are.
- All tables in select queries will now be aliased with the model names to be support schemas. This will affect people stuff like `where: {'table.attribute': value}
# v1.7.0 # v1.7.0
- [FEATURE] covers more advanced include cases with limiting and filtering (specifically cases where a include would be in the subquery but its child include wouldnt be, for cases where a 1:1 association had a 1:M association as a nested include) - [FEATURE] covers more advanced include cases with limiting and filtering (specifically cases where a include would be in the subquery but its child include wouldnt be, for cases where a 1:1 association had a 1:M association as a nested include)
......
...@@ -68,7 +68,7 @@ module.exports = (function() { ...@@ -68,7 +68,7 @@ module.exports = (function() {
var where = {} var where = {}
params = params || {} params = params || {}
params.where = [params.where] || [] params.where = (params.where && [params.where]) || []
where[association.targetIdentifier] = this.get(association.identifier) where[association.targetIdentifier] = this.get(association.identifier)
params.where.push(where) params.where.push(where)
......
...@@ -34,7 +34,7 @@ module.exports = (function() { ...@@ -34,7 +34,7 @@ module.exports = (function() {
new Utils.where( new Utils.where(
through.rawAttributes[self.association.foreignIdentifier], { through.rawAttributes[self.association.foreignIdentifier], {
join: new Utils.literal([ join: new Utils.literal([
self.QueryInterface.quoteTable(self.association.target.getTableName()), self.QueryInterface.quoteTable(self.association.target.name),
self.QueryInterface.quoteIdentifier(foreignPrimaryKey) self.QueryInterface.quoteIdentifier(foreignPrimaryKey)
].join('.')) ].join('.'))
} }
...@@ -48,28 +48,28 @@ module.exports = (function() { ...@@ -48,28 +48,28 @@ module.exports = (function() {
if (!options.attributes) { if (!options.attributes) {
options.attributes = [ options.attributes = [
self.QueryInterface.quoteTable(self.association.target.getTableName())+".*" self.QueryInterface.quoteTable(self.association.target.name)+".*"
] ]
} }
if (options.joinTableAttributes) { if (options.joinTableAttributes) {
options.joinTableAttributes.forEach(function (elem) { options.joinTableAttributes.forEach(function (elem) {
options.attributes.push( options.attributes.push(
self.QueryInterface.quoteTable(through.getTableName()) + '.' + self.QueryInterface.quoteIdentifier(elem) + ' as ' + self.QueryInterface.quoteTable(through.name) + '.' + self.QueryInterface.quoteIdentifier(elem) + ' as ' +
self.QueryInterface.quoteIdentifier(through.name + '.' + elem, true) self.QueryInterface.quoteIdentifier(through.name + '.' + elem, true)
) )
}) })
} else { } else {
Utils._.forOwn(through.rawAttributes, function (elem, key) { Utils._.forOwn(through.rawAttributes, function (elem, key) {
options.attributes.push( options.attributes.push(
self.QueryInterface.quoteTable(through.getTableName()) + '.' + self.QueryInterface.quoteIdentifier(key) + ' as ' + self.QueryInterface.quoteTable(through.name) + '.' + self.QueryInterface.quoteIdentifier(key) + ' as ' +
self.QueryInterface.quoteIdentifier(through.name + '.' + key, true) self.QueryInterface.quoteIdentifier(through.name + '.' + key, true)
) )
}) })
} }
} }
self.association.target.findAllJoin(through.getTableName(), options, queryOptions) self.association.target.findAllJoin([through.getTableName(), through.name], options, queryOptions)
.on('success', function(objects) { customEventEmitter.emit('success', objects) }) .on('success', function(objects) { customEventEmitter.emit('success', objects) })
.on('error', function(err){ customEventEmitter.emit('error', err) }) .on('error', function(err){ customEventEmitter.emit('error', err) })
.on('sql', function(sql) { customEventEmitter.emit('sql', sql)}) .on('sql', function(sql) { customEventEmitter.emit('sql', sql)})
......
...@@ -67,7 +67,7 @@ module.exports = (function() { ...@@ -67,7 +67,7 @@ module.exports = (function() {
var where = {} var where = {}
params = params || {} params = params || {}
params.where = [params.where] || [] params.where = (params.where && [params.where]) || []
where[association.identifier] = this.get(association.sourceIdentifier) where[association.identifier] = this.get(association.sourceIdentifier)
params.where.push(where) params.where.push(where)
......
...@@ -261,6 +261,7 @@ module.exports = (function() { ...@@ -261,6 +261,7 @@ module.exports = (function() {
Utils._.each(self.rawAttributes, function(options, attribute) { Utils._.each(self.rawAttributes, function(options, attribute) {
options.Model = self options.Model = self
options.fieldName = attribute options.fieldName = attribute
options._modelAttribute = true
if (options.hasOwnProperty(type)) { if (options.hasOwnProperty(type)) {
_custom[attribute] = options[type] _custom[attribute] = options[type]
...@@ -470,11 +471,11 @@ module.exports = (function() { ...@@ -470,11 +471,11 @@ module.exports = (function() {
//right now, the caller (has-many-double-linked) is in charge of the where clause //right now, the caller (has-many-double-linked) is in charge of the where clause
DAOFactory.prototype.findAllJoin = function(joinTableName, options, queryOptions) { DAOFactory.prototype.findAllJoin = function(joinTableName, options, queryOptions) {
var optcpy = Utils._.clone(options) var optcpy = Utils._.clone(options)
optcpy.attributes = optcpy.attributes || [this.QueryInterface.quoteIdentifier(this.getTableName())+".*"] optcpy.attributes = optcpy.attributes || [this.QueryInterface.quoteTable(this.name)+".*"]
// whereCollection is used for non-primary key updates // whereCollection is used for non-primary key updates
this.options.whereCollection = optcpy.where || null; this.options.whereCollection = optcpy.where || null;
return this.QueryInterface.select(this, [this.getTableName(), joinTableName], optcpy, Utils._.defaults({ return this.QueryInterface.select(this, [[this.getTableName(), this.name], joinTableName], optcpy, Utils._.defaults({
type: QueryTypes.SELECT type: QueryTypes.SELECT
}, queryOptions, { transaction: (options || {}).transaction })) }, queryOptions, { transaction: (options || {}).transaction }))
} }
...@@ -602,7 +603,7 @@ module.exports = (function() { ...@@ -602,7 +603,7 @@ module.exports = (function() {
return new Utils.CustomEventEmitter(function (emitter) { return new Utils.CustomEventEmitter(function (emitter) {
var col = this.sequelize.col('*') var col = this.sequelize.col('*')
if (options.include) { if (options.include) {
col = this.sequelize.col(this.getTableName()+'.'+(this.primaryKeyAttributes[0] || 'id')) col = this.sequelize.col(this.name+'.'+(this.primaryKeyAttribute))
} }
options.attributes = [ options.attributes = [
...@@ -1286,8 +1287,8 @@ module.exports = (function() { ...@@ -1286,8 +1287,8 @@ module.exports = (function() {
return options return options
} }
if(this.tableName) { if(this.name || this.tableName) {
quoteIdentifiedDeletedAtCol = this.QueryInterface.quoteIdentifier(this.tableName) + '.' + quoteIdentifiedDeletedAtCol quoteIdentifiedDeletedAtCol = this.QueryInterface.quoteIdentifier(this.name || this.tableName) + '.' + quoteIdentifiedDeletedAtCol
} }
if (typeof options.where === "string") { if (typeof options.where === "string") {
......
...@@ -448,7 +448,7 @@ module.exports = (function() { ...@@ -448,7 +448,7 @@ module.exports = (function() {
*/ */
DAO.prototype.reload = function(options) { DAO.prototype.reload = function(options) {
var where = [ var where = [
this.QueryInterface.quoteIdentifier(this.Model.tableName) + '.' + this.QueryInterface.quoteIdentifier(this.Model.primaryKeyAttribute)+'=?', this.QueryInterface.quoteTable(this.Model.name) + '.' + this.QueryInterface.quoteIdentifier(this.Model.primaryKeyAttribute)+'=?',
this.get(this.Model.primaryKeyAttribute, {raw: true}) this.get(this.Model.primaryKeyAttribute, {raw: true})
] ]
......
...@@ -14,6 +14,8 @@ module.exports = (function() { ...@@ -14,6 +14,8 @@ module.exports = (function() {
return { return {
tableName: param.tableName || param, tableName: param.tableName || param,
table: param.tableName || param,
name: param.name || param,
schema: schema, schema: schema,
delimiter: schemaDelimiter || '.', delimiter: schemaDelimiter || '.',
toString: function() { toString: function() {
...@@ -350,10 +352,14 @@ module.exports = (function() { ...@@ -350,10 +352,14 @@ module.exports = (function() {
}, },
quoteTable: function(param) { quoteTable: function(param, as) {
if (_.isObject(param)) { var table = '';
var table = '';
if (as === true) {
as = param.as || param.name || param
}
if (_.isObject(param)) {
if (this._dialect.supports.schemas) { if (this._dialect.supports.schemas) {
if (param.schema) { if (param.schema) {
table += this.quoteIdentifier(param.schema) + '.' table += this.quoteIdentifier(param.schema) + '.'
...@@ -369,9 +375,15 @@ module.exports = (function() { ...@@ -369,9 +375,15 @@ module.exports = (function() {
table = this.quoteIdentifier(table) table = this.quoteIdentifier(table)
} }
return table
} else {
table = this.quoteIdentifier(param)
}
if (as) {
table += " AS " + this.quoteIdentifier(as)
} }
return this.quoteIdentifier(param) return table
}, },
/* /*
...@@ -406,7 +418,7 @@ module.exports = (function() { ...@@ -406,7 +418,7 @@ module.exports = (function() {
, len = obj.length , len = obj.length
for (var 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 (item._modelAttribute || Utils._.isString(item) || item instanceof Utils.fn || item instanceof Utils.col || item instanceof Utils.literal || item instanceof Utils.cast || 'raw' in item) {
break break
} }
...@@ -443,6 +455,8 @@ module.exports = (function() { ...@@ -443,6 +455,8 @@ module.exports = (function() {
sql += ' ' + obj[i + 1] sql += ' ' + obj[i + 1]
} }
return sql return sql
} else if (obj._modelAttribute) {
return this.quoteTable(obj.Model.name)+'.'+obj.fieldName
} else if (obj instanceof Utils.fn || obj instanceof Utils.col || obj instanceof Utils.literal || obj instanceof Utils.cast) { } else if (obj instanceof Utils.fn || obj instanceof Utils.col || obj instanceof Utils.literal || obj instanceof Utils.cast) {
return obj.toString(this) return obj.toString(this)
} else if (Utils._.isObject(obj) && 'raw' in obj) { } else if (Utils._.isObject(obj) && 'raw' in obj) {
...@@ -579,10 +593,16 @@ module.exports = (function() { ...@@ -579,10 +593,16 @@ module.exports = (function() {
, subQueryItems = [] , subQueryItems = []
, subQueryAttributes = null , subQueryAttributes = null
, subJoinQueries = [] , subJoinQueries = []
, mainTableAs = null
// Escape table
if (!Array.isArray(tableName) && Model) {
options.tableAs = mainTableAs = this.quoteTable(Model.name)
}
options.table = table = !Array.isArray(tableName) ? this.quoteTable(tableName) : tableName.map(function(t) { options.table = table = !Array.isArray(tableName) ? this.quoteTable(tableName) : tableName.map(function(t) {
return this.quoteTable(t) if (Array.isArray(t)) {
return this.quoteTable(t[0], t[1])
}
return this.quoteTable(t, true)
}.bind(this)).join(", ") }.bind(this)).join(", ")
if (subQuery && mainAttributes) { if (subQuery && mainAttributes) {
...@@ -620,25 +640,25 @@ module.exports = (function() { ...@@ -620,25 +640,25 @@ module.exports = (function() {
} }
if (options.include && attr.indexOf('.') === -1 && addTable) { if (options.include && attr.indexOf('.') === -1 && addTable) {
attr = this.quoteTable(options.table) + '.' + attr attr = mainTableAs + '.' + attr
} }
return attr return attr
}.bind(this)) }.bind(this))
// If no attributes specified, use * // If no attributes specified, use *
mainAttributes = mainAttributes || (options.include ? [options.table+'.*'] : ['*']) mainAttributes = mainAttributes || (options.include ? [mainTableAs+'.*'] : ['*'])
// If subquery, we ad the mainAttributes to the subQuery and set the mainAttributes to select * from subquery // If subquery, we ad the mainAttributes to the subQuery and set the mainAttributes to select * from subquery
if (subQuery) { if (subQuery) {
// We need primary keys // We need primary keys
subQueryAttributes = mainAttributes subQueryAttributes = mainAttributes
mainAttributes = [options.table+'.*'] mainAttributes = [mainTableAs+'.*']
} }
if (options.include) { if (options.include) {
var generateJoinQueries = function(include, parentTable) { var generateJoinQueries = function(include, parentTable) {
var table = include.daoFactory.tableName var table = include.daoFactory.getTableName()
, as = include.as , as = include.as
, joinQueryItem = "" , joinQueryItem = ""
, joinQueries = { , joinQueries = {
...@@ -654,7 +674,7 @@ module.exports = (function() { ...@@ -654,7 +674,7 @@ module.exports = (function() {
whereOptions.keysEscaped = true whereOptions.keysEscaped = true
if (tableName !== parentTable) { if (tableName !== parentTable && mainTableAs !== parentTable) {
as = parentTable+'.'+include.as as = parentTable+'.'+include.as
} }
...@@ -672,7 +692,7 @@ module.exports = (function() { ...@@ -672,7 +692,7 @@ module.exports = (function() {
} }
if (through) { if (through) {
var throughTable = through.daoFactory.tableName var throughTable = through.daoFactory.getTableName()
, throughAs = as + "." + through.as , throughAs = as + "." + through.as
, throughAttributes = through.attributes.map(function(attr) { , throughAttributes = through.attributes.map(function(attr) {
return self.quoteIdentifier(throughAs) + "." + self.quoteIdentifier(attr) + " AS " + self.quoteIdentifier(throughAs + "." + attr) return self.quoteIdentifier(throughAs) + "." + self.quoteIdentifier(attr) + " AS " + self.quoteIdentifier(throughAs + "." + attr)
...@@ -699,7 +719,7 @@ module.exports = (function() { ...@@ -699,7 +719,7 @@ module.exports = (function() {
// Filter statement for left side of through // Filter statement for left side of through
// Used by both join and subquery where // Used by both join and subquery where
sourceJoinOn = self.quoteIdentifier(tableSource) + "." + self.quoteIdentifier(attrSource) + " = " sourceJoinOn = self.quoteTable(tableSource) + "." + self.quoteIdentifier(attrSource) + " = "
sourceJoinOn += self.quoteIdentifier(throughAs) + "." + self.quoteIdentifier(identSource) sourceJoinOn += self.quoteIdentifier(throughAs) + "." + self.quoteIdentifier(identSource)
// Filter statement for right side of through // Filter statement for right side of through
...@@ -708,11 +728,11 @@ module.exports = (function() { ...@@ -708,11 +728,11 @@ module.exports = (function() {
targetJoinOn += self.quoteIdentifier(throughAs) + "." + self.quoteIdentifier(identTarget) targetJoinOn += self.quoteIdentifier(throughAs) + "." + self.quoteIdentifier(identTarget)
// Generate join SQL for left side of through // Generate join SQL for left side of through
joinQueryItem += joinType + self.quoteIdentifier(throughTable) + " AS " + self.quoteIdentifier(throughAs) + " ON " joinQueryItem += joinType + self.quoteTable(throughTable, throughAs) + " ON "
joinQueryItem += sourceJoinOn joinQueryItem += sourceJoinOn
// Generate join SQL for right side of through // Generate join SQL for right side of through
joinQueryItem += joinType + self.quoteTable(table) + " AS " + self.quoteIdentifier(as) + " ON " joinQueryItem += joinType + self.quoteTable(table, as) + " ON "
joinQueryItem += targetJoinOn joinQueryItem += targetJoinOn
...@@ -724,8 +744,8 @@ module.exports = (function() { ...@@ -724,8 +744,8 @@ module.exports = (function() {
// Creating the as-is where for the subQuery, checks that the required association exists // Creating the as-is where for the subQuery, checks that the required association exists
var _where = "("; var _where = "(";
_where += "SELECT "+self.quoteIdentifier(identSource)+" FROM " + self.quoteIdentifier(throughTable) + " AS " + self.quoteIdentifier(throughAs); _where += "SELECT "+self.quoteIdentifier(identSource)+" FROM " + self.quoteTable(throughTable, throughAs);
_where += joinType + self.quoteTable(table) + " AS " + self.quoteIdentifier(as) + " ON "+targetJoinOn; _where += joinType + self.quoteTable(table, as) + " ON "+targetJoinOn;
_where += " WHERE " + sourceJoinOn + " AND " + targetWhere + " LIMIT 1" _where += " WHERE " + sourceJoinOn + " AND " + targetWhere + " LIMIT 1"
_where += ")"; _where += ")";
_where += " IS NOT NULL" _where += " IS NOT NULL"
...@@ -752,7 +772,7 @@ module.exports = (function() { ...@@ -752,7 +772,7 @@ module.exports = (function() {
where += self.quoteTable(tableRight) + "." + self.quoteIdentifier(attrRight) where += self.quoteTable(tableRight) + "." + self.quoteIdentifier(attrRight)
// Generate join SQL // Generate join SQL
joinQueryItem += joinType + self.quoteTable(table) + " AS " + self.quoteIdentifier(as) + " ON " joinQueryItem += joinType + self.quoteTable(table, as) + " ON "
joinQueryItem += where joinQueryItem += where
if (include.where) { if (include.where) {
...@@ -761,8 +781,9 @@ module.exports = (function() { ...@@ -761,8 +781,9 @@ module.exports = (function() {
// If its a multi association we need to add a where query to the main where (executed in the subquery) // If its a multi association we need to add a where query to the main where (executed in the subquery)
if (subQuery && association.isMultiAssociation) { if (subQuery && association.isMultiAssociation) {
if (!options.where) options.where = {} if (!options.where) options.where = {}
// Creating the as-is where for the subQuery, checks that the required association exists // Creating the as-is where for the subQuery, checks that the required association exists
options.where["__"+as] = self.sequelize.asIs("(SELECT "+self.quoteIdentifier(attrRight)+" FROM " + self.quoteIdentifier(tableRight) + " WHERE " + where + " LIMIT 1) IS NOT NULL") options.where["__"+as] = self.sequelize.asIs("(SELECT "+self.quoteIdentifier(attrRight)+" FROM " + self.quoteTable(table, as) + " WHERE " + where + " LIMIT 1) IS NOT NULL")
} }
} }
} }
...@@ -790,7 +811,7 @@ module.exports = (function() { ...@@ -790,7 +811,7 @@ module.exports = (function() {
// Loop through includes and generate subqueries // Loop through includes and generate subqueries
options.include.forEach(function(include) { options.include.forEach(function(include) {
var joinQueries = generateJoinQueries(include, tableName) var joinQueries = generateJoinQueries(include, options.tableAs)
subJoinQueries = subJoinQueries.concat(joinQueries.subQuery) subJoinQueries = subJoinQueries.concat(joinQueries.subQuery)
mainJoinQueries = mainJoinQueries.concat(joinQueries.mainQuery) mainJoinQueries = mainJoinQueries.concat(joinQueries.mainQuery)
...@@ -800,18 +821,24 @@ module.exports = (function() { ...@@ -800,18 +821,24 @@ module.exports = (function() {
// If using subQuery select defined subQuery attributes and join subJoinQueries // If using subQuery select defined subQuery attributes and join subJoinQueries
if (subQuery) { if (subQuery) {
subQueryItems.push("SELECT " + subQueryAttributes.join(', ') + " FROM " + options.table) subQueryItems.push("SELECT " + subQueryAttributes.join(', ') + " FROM " + options.table)
if (mainTableAs) {
subQueryItems.push(" AS "+mainTableAs)
}
subQueryItems.push(subJoinQueries.join('')) subQueryItems.push(subJoinQueries.join(''))
// Else do it the reguar way // Else do it the reguar way
} else { } else {
mainQueryItems.push("SELECT " + mainAttributes.join(', ') + " FROM " + options.table) mainQueryItems.push("SELECT " + mainAttributes.join(', ') + " FROM " + options.table)
if (mainTableAs) {
mainQueryItems.push(" AS "+mainTableAs)
}
mainQueryItems.push(mainJoinQueries.join('')) mainQueryItems.push(mainJoinQueries.join(''))
} }
// Add WHERE to sub or main query // Add WHERE to sub or main query
if (options.hasOwnProperty('where')) { if (options.hasOwnProperty('where')) {
options.where = this.getWhereConditions(options.where, tableName, Model, options) options.where = this.getWhereConditions(options.where, mainTableAs || tableName, Model, options)
if (subQuery) { if (subQuery) {
subQueryItems.push(" WHERE " + options.where) subQueryItems.push(" WHERE " + options.where)
} else { } else {
...@@ -878,7 +905,7 @@ module.exports = (function() { ...@@ -878,7 +905,7 @@ module.exports = (function() {
if (subQuery) { if (subQuery) {
query = "SELECT " + mainAttributes.join(', ') + " FROM (" query = "SELECT " + mainAttributes.join(', ') + " FROM ("
query += subQueryItems.join('') query += subQueryItems.join('')
query += ") AS "+options.table query += ") AS "+options.tableAs
query += mainJoinQueries.join('') query += mainJoinQueries.join('')
query += mainQueryItems.join('') query += mainQueryItems.join('')
} else { } else {
...@@ -959,6 +986,9 @@ module.exports = (function() { ...@@ -959,6 +986,9 @@ module.exports = (function() {
if (Array.isArray(tableName)) { if (Array.isArray(tableName)) {
tableName = tableName[0] tableName = tableName[0]
if (Array.isArray(tableName)) {
tableName = tableName[1]
}
} }
options = options || {} options = options || {}
...@@ -979,7 +1009,7 @@ module.exports = (function() { ...@@ -979,7 +1009,7 @@ module.exports = (function() {
result = "(" + result + ")" result = "(" + result + ")"
} else if (smth instanceof Utils.where) { } else if (smth instanceof Utils.where) {
var value = smth.logic var value = smth.logic
, key = this.quoteTable(smth.attribute.Model.getTableName())+'.'+this.quoteIdentifier(smth.attribute.fieldName) , key = this.quoteTable(smth.attribute.Model.name)+'.'+this.quoteIdentifier(smth.attribute.fieldName)
, logic , logic
, _result = [] , _result = []
, _value , _value
......
...@@ -279,7 +279,7 @@ module.exports = (function() { ...@@ -279,7 +279,7 @@ module.exports = (function() {
}.bind(this)) }.bind(this))
var replacements = { var replacements = {
table: this.quoteIdentifiers(tableName) table: this.quoteTable(tableName)
, attributes: allAttributes.map(function(attr){ , attributes: allAttributes.map(function(attr){
return this.quoteIdentifier(attr) return this.quoteIdentifier(attr)
}.bind(this)).join(",") }.bind(this)).join(",")
......
...@@ -329,8 +329,7 @@ module.exports = (function() { ...@@ -329,8 +329,7 @@ module.exports = (function() {
schemaDelimiter: schemaDelimiter:
schemaDelimiter schemaDelimiter
} }
}), })
this.QueryGenerator.options.quoteIdentifiers
) )
sql = 'DESCRIBE ' + table + ';' sql = 'DESCRIBE ' + table + ';'
} }
......
...@@ -127,7 +127,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -127,7 +127,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
this.Article.hasMany(this.Label) this.Article.hasMany(this.Label)
this.sequelize.sync({ force: true }).success(function() { this.sequelize.sync({ force: true }).done(function(err) {
expect(err).not.to.be.ok
done() done()
}) })
}) })
...@@ -139,7 +140,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -139,7 +140,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
Article.hasMany(Label) Article.hasMany(Label)
sequelize.sync({ force: true }).success(function() { sequelize.sync({ force: true }).done(function(err) {
expect(err).not.to.be.ok
Article.create({ title: 'foo' }).success(function(article) { Article.create({ title: 'foo' }).success(function(article) {
Label.create({ text: 'bar' }).success(function(label) { Label.create({ text: 'bar' }).success(function(label) {
sequelize.transaction(function(t) { sequelize.transaction(function(t) {
...@@ -615,7 +617,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -615,7 +617,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}) })
it("get associated objects with an eager load", function(done) { it("get associated objects with an eager load", function(done) {
this.User.find({where: {username: 'John'}, include: [ this.Task ]}).success(function (john) { this.User.find({where: {username: 'John'}, include: [ this.Task ]}).done(function (err, john) {
expect(err).not.to.be.ok
expect(john.tasks).to.have.length(2); expect(john.tasks).to.have.length(2);
done(); done();
}) })
......
...@@ -17,12 +17,13 @@ describe(Support.getTestDialectTeaser("Self"), function() { ...@@ -17,12 +17,13 @@ describe(Support.getTestDialectTeaser("Self"), function() {
freezeTableName: true freezeTableName: true
}); });
Group.belongsTo(Group, { foreignKey: 'parent' }); Group.belongsTo(Group, { as: 'Parent', foreignKey: 'parent_id' });
Group.sync({force: true}).done(function (err) { Group.sync({force: true}).done(function (err) {
expect(err).not.to.be.ok expect(err).not.to.be.ok
Group.findAll({ Group.findAll({
include: [{ include: [{
model: Group model: Group,
as: 'Parent'
}] }]
}).done(function (err) { }).done(function (err) {
expect(err).not.to.be.ok expect(err).not.to.be.ok
......
...@@ -1937,17 +1937,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -1937,17 +1937,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
var tableName = '' var tableName = ''
, ident = this.sequelize.queryInterface.QueryGenerator.quoteIdentifier , ident = this.sequelize.queryInterface.QueryGenerator.quoteIdentifier
, escape = this.sequelize.queryInterface.QueryGenerator.escape , escape = this.sequelize.queryInterface.QueryGenerator.escape
if(this.Project.tableName) {
tableName = ident(this.Project.tableName) + '.'
}
this.User.findAll({ this.User.findAll({
where: [ where: [
tableName + ident('title') + ' = ' + escape('republic') this.sequelize.queryInterface.QueryGenerator.quoteIdentifiers('Projects.title') + ' = ' + escape('republic')
], ],
include: [ include: [
{model: this.Project} {model: this.Project}
] ]
}).success(function(users){ }).done(function(err, users){
expect(err).not.to.be.ok
try{ try{
expect(users.length).to.be.equal(1) expect(users.length).to.be.equal(1)
...@@ -1956,14 +1955,15 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -1956,14 +1955,15 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}catch(e){ }catch(e){
done(e) done(e)
} }
}).error(done) })
}) })
it('should not overwrite a specified deletedAt', function(done) { it('should not overwrite a specified deletedAt', function(done) {
var tableName = '' var tableName = ''
, ident = this.sequelize.queryInterface.QueryGenerator.quoteIdentifier , ident = this.sequelize.queryInterface.QueryGenerator.quoteIdentifier
if(this.User.tableName) {
tableName = ident(this.User.tableName) + '.' if(this.User.name) {
tableName = ident(this.User.name) + '.'
} }
this.User.findAll({ this.User.findAll({
where: [ where: [
......
...@@ -59,10 +59,10 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -59,10 +59,10 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
where: Sequelize[method]( { username: "foo", intVal: 2 }, { secretValue: 'bar' } ) where: Sequelize[method]( { username: "foo", intVal: 2 }, { secretValue: 'bar' } )
}).on('sql', function(sql) { }).on('sql', function(sql) {
var expectation = ({ var expectation = ({
mysql: "WHERE (`Users`.`username`='foo' AND `Users`.`intVal`=2 " + word + " `Users`.`secretValue`='bar')", mysql: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')",
sqlite: "WHERE (`Users`.`username`='foo' AND `Users`.`intVal`=2 " + word + " `Users`.`secretValue`='bar')", sqlite: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')",
postgres: 'WHERE ("Users"."username"=\'foo\' AND "Users"."intVal"=2 ' + word + ' "Users"."secretValue"=\'bar\')', postgres: 'WHERE ("User"."username"=\'foo\' AND "User"."intVal"=2 ' + word + ' "User"."secretValue"=\'bar\')',
mariadb: "WHERE (`Users`.`username`='foo' AND `Users`.`intVal`=2 " + word + " `Users`.`secretValue`='bar')" mariadb: "WHERE (`User`.`username`='foo' AND `User`.`intVal`=2 " + word + " `User`.`secretValue`='bar')"
})[Support.getTestDialect()] })[Support.getTestDialect()]
if (!expectation) { if (!expectation) {
...@@ -81,10 +81,10 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -81,10 +81,10 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
where: Sequelize[method]( 1, 2 ) where: Sequelize[method]( 1, 2 )
}).on('sql', function(sql) { }).on('sql', function(sql) {
var expectation = ({ var expectation = ({
mysql: "WHERE (`Users`.`id`=1 " + word + " `Users`.`id`=2)", mysql: "WHERE (`User`.`id`=1 " + word + " `User`.`id`=2)",
sqlite: "WHERE (`Users`.`id`=1 " + word + " `Users`.`id`=2)", sqlite: "WHERE (`User`.`id`=1 " + word + " `User`.`id`=2)",
postgres: 'WHERE ("Users"."id"=1 ' + word + ' "Users"."id"=2)', postgres: 'WHERE ("User"."id"=1 ' + word + ' "User"."id"=2)',
mariadb: "WHERE (`Users`.`id`=1 " + word + " `Users`.`id`=2)" mariadb: "WHERE (`User`.`id`=1 " + word + " `User`.`id`=2)"
})[Support.getTestDialect()] })[Support.getTestDialect()]
if (!expectation) { if (!expectation) {
...@@ -150,16 +150,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -150,16 +150,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
if (Support.getTestDialect() === 'postgres') { if (Support.getTestDialect() === 'postgres') {
expect(sql).to.contain( expect(sql).to.contain(
'WHERE (' + [ 'WHERE (' + [
'"Users"."id"=42 AND 2=2 AND 1=1 AND "Users"."username"=\'foo\' AND ', '"User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\' AND ',
'(', '(',
'"Users"."id"=42 OR 2=2 OR 1=1 OR "Users"."username"=\'foo\' OR ', '"User"."id"=42 OR 2=2 OR 1=1 OR "User"."username"=\'foo\' OR ',
'("Users"."id"=42 AND 2=2 AND 1=1 AND "Users"."username"=\'foo\') OR ', '("User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\') OR ',
'("Users"."id"=42 OR 2=2 OR 1=1 OR "Users"."username"=\'foo\')', '("User"."id"=42 OR 2=2 OR 1=1 OR "User"."username"=\'foo\')',
') AND ', ') AND ',
'(', '(',
'"Users"."id"=42 AND 2=2 AND 1=1 AND "Users"."username"=\'foo\' AND ', '"User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\' AND ',
'("Users"."id"=42 OR 2=2 OR 1=1 OR "Users"."username"=\'foo\') AND ', '("User"."id"=42 OR 2=2 OR 1=1 OR "User"."username"=\'foo\') AND ',
'("Users"."id"=42 AND 2=2 AND 1=1 AND "Users"."username"=\'foo\')', '("User"."id"=42 AND 2=2 AND 1=1 AND "User"."username"=\'foo\')',
')' ')'
].join("") + ].join("") +
')' ')'
...@@ -167,16 +167,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -167,16 +167,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
} else { } else {
expect(sql).to.contain( expect(sql).to.contain(
"WHERE (" + [ "WHERE (" + [
"`Users`.`id`=42 AND 2=2 AND 1=1 AND `Users`.`username`='foo' AND ", "`User`.`id`=42 AND 2=2 AND 1=1 AND `User`.`username`='foo' AND ",
"(", "(",
"`Users`.`id`=42 OR 2=2 OR 1=1 OR `Users`.`username`='foo' OR ", "`User`.`id`=42 OR 2=2 OR 1=1 OR `User`.`username`='foo' OR ",
"(`Users`.`id`=42 AND 2=2 AND 1=1 AND `Users`.`username`='foo') OR ", "(`User`.`id`=42 AND 2=2 AND 1=1 AND `User`.`username`='foo') OR ",
"(`Users`.`id`=42 OR 2=2 OR 1=1 OR `Users`.`username`='foo')", "(`User`.`id`=42 OR 2=2 OR 1=1 OR `User`.`username`='foo')",
") AND ", ") AND ",
"(", "(",
"`Users`.`id`=42 AND 2=2 AND 1=1 AND `Users`.`username`='foo' AND ", "`User`.`id`=42 AND 2=2 AND 1=1 AND `User`.`username`='foo' AND ",
"(`Users`.`id`=42 OR 2=2 OR 1=1 OR `Users`.`username`='foo') AND ", "(`User`.`id`=42 OR 2=2 OR 1=1 OR `User`.`username`='foo') AND ",
"(`Users`.`id`=42 AND 2=2 AND 1=1 AND `Users`.`username`='foo')", "(`User`.`id`=42 AND 2=2 AND 1=1 AND `User`.`username`='foo')",
")" ")"
].join("") + ].join("") +
")" ")"
......
...@@ -617,7 +617,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -617,7 +617,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
Page.create({ content: 'om nom nom' }).success(function(page) { Page.create({ content: 'om nom nom' }).success(function(page) {
book.setPages([ page ]).success(function() { book.setPages([ page ]).success(function() {
Book.find({ Book.find({
where: (dialect === 'postgres' ? '"Books"."id"=' : '`Books`.`id`=') + book.id, where: (dialect === 'postgres' ? '"Book"."id"=' : '`Book`.`id`=') + book.id,
include: [Page] include: [Page]
}).success(function(leBook) { }).success(function(leBook) {
page.updateAttributes({ content: 'something totally different' }).success(function(page) { page.updateAttributes({ content: 'something totally different' }).success(function(page) {
......
...@@ -394,7 +394,7 @@ describe(Support.getTestDialectTeaser("Include"), function () { ...@@ -394,7 +394,7 @@ describe(Support.getTestDialectTeaser("Include"), function () {
]} ]}
], ],
order: [ order: [
['Users.id', 'ASC'] ['User.id', 'ASC']
] ]
}).done(function (err, users) { }).done(function (err, users) {
expect(err).not.to.be.ok expect(err).not.to.be.ok
...@@ -1394,7 +1394,7 @@ describe(Support.getTestDialectTeaser("Include"), function () { ...@@ -1394,7 +1394,7 @@ describe(Support.getTestDialectTeaser("Include"), function () {
], ],
limit: 3, limit: 3,
order: [ order: [
[self.sequelize.col(self.models.Product.tableName+'.id'), 'ASC'] [self.sequelize.col(self.models.Product.name+'.id'), 'ASC']
] ]
}).done(function (err, products) { }).done(function (err, products) {
expect(err).not.to.be.ok expect(err).not.to.be.ok
......
/* jshint camelcase: false */
/* jshint expr: true */
var chai = require('chai')
, Sequelize = require('../../index')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + "/../../lib/data-types")
, dialect = Support.getTestDialect()
, config = require(__dirname + "/../config/config")
, sinon = require('sinon')
, datetime = require('chai-datetime')
, _ = require('lodash')
, moment = require('moment')
, async = require('async')
chai.use(datetime)
chai.Assertion.includeStack = true
var sortById = function(a, b) {
return a.id < b.id ? -1 : 1
}
describe(Support.getTestDialectTeaser("Includes with schemas"), function () {
describe('findAll', function () {
beforeEach(function () {
var self = this
this.fixtureA = function(done) {
self.sequelize.dropAllSchemas().success(function(){
self.sequelize.createSchema("account").success(function(){
var AccUser = self.sequelize.define("AccUser", {}, {schema: "account"})
, Company = self.sequelize.define("Company", {
name: DataTypes.STRING
}, {schema: "account"})
, Product = self.sequelize.define("Product", {
title: DataTypes.STRING
}, {schema: "account"})
, Tag = self.sequelize.define("Tag", {
name: DataTypes.STRING
}, {schema: "account"})
, Price = self.sequelize.define("Price", {
value: DataTypes.FLOAT
}, {schema: "account"})
, Customer = self.sequelize.define("Customer", {
name: DataTypes.STRING
}, {schema: "account"})
, Group = self.sequelize.define("Group", {
name: DataTypes.STRING
}, {schema: "account"})
, GroupMember = self.sequelize.define("GroupMember", {
}, {schema: "account"})
, Rank = self.sequelize.define("Rank", {
name: DataTypes.STRING,
canInvite: {
type: DataTypes.INTEGER,
defaultValue: 0
},
canRemove: {
type: DataTypes.INTEGER,
defaultValue: 0
},
canPost: {
type: DataTypes.INTEGER,
defaultValue: 0
}
}, {schema: "account"})
self.models = {
AccUser: AccUser,
Company: Company,
Product: Product,
Tag: Tag,
Price: Price,
Customer: Customer,
Group: Group,
GroupMember: GroupMember,
Rank: Rank
}
AccUser.hasMany(Product)
Product.belongsTo(AccUser)
Product.hasMany(Tag)
Tag.hasMany(Product)
Product.belongsTo(Tag, {as: 'Category'})
Product.belongsTo(Company)
Product.hasMany(Price)
Price.belongsTo(Product)
AccUser.hasMany(GroupMember, {as: 'Memberships'})
GroupMember.belongsTo(AccUser)
GroupMember.belongsTo(Rank)
GroupMember.belongsTo(Group)
Group.hasMany(GroupMember, {as: 'Memberships'})
self.sequelize.sync({force: true}).done(function () {
var count = 4
, i = -1
async.auto({
groups: function(callback) {
Group.bulkCreate([
{name: 'Developers'},
{name: 'Designers'},
{name: 'Managers'}
]).done(function () {
Group.findAll().done(callback)
})
},
companies: function(callback) {
Company.bulkCreate([
{name: 'Sequelize'},
{name: 'Coca Cola'},
{name: 'Bonanza'},
{name: 'NYSE'},
{name: 'Coshopr'}
]).done(function (err) {
if (err) return callback(err);
Company.findAll().done(callback)
})
},
ranks: function(callback) {
Rank.bulkCreate([
{name: 'Admin', canInvite: 1, canRemove: 1, canPost: 1},
{name: 'Trustee', canInvite: 1, canRemove: 0, canPost: 1},
{name: 'Member', canInvite: 1, canRemove: 0, canPost: 0}
]).done(function (err) {
Rank.findAll().done(callback)
})
},
tags: function(callback) {
Tag.bulkCreate([
{name: 'A'},
{name: 'B'},
{name: 'C'},
{name: 'D'},
{name: 'E'}
]).done(function () {
Tag.findAll().done(callback)
})
},
loop: ['groups', 'ranks', 'tags', 'companies', function (done, results) {
var groups = results.groups
, ranks = results.ranks
, tags = results.tags
, companies = results.companies
async.whilst(
function () { return i < count; },
function (callback) {
i++
async.auto({
user: function (callback) {
AccUser.create().done(callback)
},
memberships: ['user', function (callback, results) {
var groupMembers = [
{AccUserId: results.user.id, GroupId: groups[0].id, RankId: ranks[0].id},
{AccUserId: results.user.id, GroupId: groups[1].id, RankId: ranks[2].id}
]
if (i < 3) {
groupMembers.push({AccUserId: results.user.id, GroupId: groups[2].id, RankId: ranks[1].id})
}
GroupMember.bulkCreate(groupMembers).done(callback)
}],
products: function (callback) {
Product.bulkCreate([
{title: 'Chair'},
{title: 'Desk'},
{title: 'Bed'},
{title: 'Pen'},
{title: 'Monitor'}
]).done(function (err) {
if (err) return callback(err);
Product.findAll().done(callback)
})
},
userProducts: ['user', 'products', function (callback, results) {
results.user.setProducts([
results.products[(i * 5)+0],
results.products[(i * 5)+1],
results.products[(i * 5)+3]
]).done(callback)
}],
productTags: ['products', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.products[(i * 5) + 0].setTags([
tags[0],
tags[2]
]))
chainer.add(results.products[(i * 5) + 1].setTags([
tags[1]
]))
chainer.add(results.products[(i * 5) + 0].setCategory(tags[1]))
chainer.add(results.products[(i * 5) + 2].setTags([
tags[0]
]))
chainer.add(results.products[(i * 5) + 3].setTags([
tags[0]
]))
chainer.run().done(callback)
}],
companies: ['products', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
results.products[(i * 5)+0].setCompany(companies[4])
results.products[(i * 5)+1].setCompany(companies[3])
results.products[(i * 5)+2].setCompany(companies[2])
results.products[(i * 5)+3].setCompany(companies[1])
results.products[(i * 5)+4].setCompany(companies[0])
chainer.run().done(callback)
}],
prices: ['products', function (callback, results) {
Price.bulkCreate([
{ProductId: results.products[(i * 5) + 0].id, value: 5},
{ProductId: results.products[(i * 5) + 0].id, value: 10},
{ProductId: results.products[(i * 5) + 1].id, value: 5},
{ProductId: results.products[(i * 5) + 1].id, value: 10},
{ProductId: results.products[(i * 5) + 1].id, value: 15},
{ProductId: results.products[(i * 5) + 1].id, value: 20},
{ProductId: results.products[(i * 5) + 2].id, value: 20},
{ProductId: results.products[(i * 5) + 3].id, value: 20}
]).done(callback)
}]
}, callback)
},
function (err) {
expect(err).not.to.be.ok
done()
}
)
}]
}, done.bind(this))
}).error(done)
})
})
}
})
it('should support an include with multiple different association types', function (done) {
var self = this
self.sequelize.dropAllSchemas().success(function(){
self.sequelize.createSchema("account").success(function(){
var AccUser = self.sequelize.define("AccUser", {}, {schema: "account"})
, Product = self.sequelize.define("Product", {
title: DataTypes.STRING
}, {schema: "account"})
, Tag = self.sequelize.define("Tag", {
name: DataTypes.STRING
}, {schema: "account"})
, Price = self.sequelize.define("Price", {
value: DataTypes.FLOAT
}, {schema: "account"})
, Customer = self.sequelize.define("Customer", {
name: DataTypes.STRING
}, {schema: "account"})
, Group = self.sequelize.define("Group", {
name: DataTypes.STRING
}, {schema: "account"})
, GroupMember = self.sequelize.define("GroupMember", {
}, {schema: "account"})
, Rank = self.sequelize.define("Rank", {
name: DataTypes.STRING,
canInvite: {
type: DataTypes.INTEGER,
defaultValue: 0
},
canRemove: {
type: DataTypes.INTEGER,
defaultValue: 0
}
}, {schema: "account"})
AccUser.hasMany(Product)
Product.belongsTo(AccUser)
Product.hasMany(Tag)
Tag.hasMany(Product)
Product.belongsTo(Tag, {as: 'Category'})
Product.hasMany(Price)
Price.belongsTo(Product)
AccUser.hasMany(GroupMember, {as: 'Memberships'})
GroupMember.belongsTo(AccUser)
GroupMember.belongsTo(Rank)
GroupMember.belongsTo(Group)
Group.hasMany(GroupMember, {as: 'Memberships'})
self.sequelize.sync({force: true}).done(function () {
var count = 4
, i = -1
async.auto({
groups: function(callback) {
Group.bulkCreate([
{name: 'Developers'},
{name: 'Designers'}
]).done(function () {
Group.findAll().done(callback)
})
},
ranks: function(callback) {
Rank.bulkCreate([
{name: 'Admin', canInvite: 1, canRemove: 1},
{name: 'Member', canInvite: 1, canRemove: 0}
]).done(function () {
Rank.findAll().done(callback)
})
},
tags: function(callback) {
Tag.bulkCreate([
{name: 'A'},
{name: 'B'},
{name: 'C'}
]).done(function () {
Tag.findAll().done(callback)
})
},
loop: ['groups', 'ranks', 'tags', function (done, results) {
var groups = results.groups
, ranks = results.ranks
, tags = results.tags
async.whilst(
function () { return i < count; },
function (callback) {
i++
async.auto({
user: function (callback) {
AccUser.create().done(callback)
},
memberships: ['user', function (callback, results) {
GroupMember.bulkCreate([
{AccUserId: results.user.id, GroupId: groups[0].id, RankId: ranks[0].id},
{AccUserId: results.user.id, GroupId: groups[1].id, RankId: ranks[1].id}
]).done(callback)
}],
products: function (callback) {
Product.bulkCreate([
{title: 'Chair'},
{title: 'Desk'}
]).done(function () {
Product.findAll().done(callback)
})
},
userProducts: ['user', 'products', function (callback, results) {
results.user.setProducts([
results.products[(i * 2)+0],
results.products[(i * 2)+1]
]).done(callback)
}],
productTags: ['products', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.products[(i * 2) + 0].setTags([
tags[0],
tags[2]
]))
chainer.add(results.products[(i * 2) + 1].setTags([
tags[1]
]))
chainer.add(results.products[(i * 2) + 0].setCategory(tags[1]))
chainer.run().done(callback)
}],
prices: ['products', function (callback, results) {
Price.bulkCreate([
{ProductId: results.products[(i * 2) + 0].id, value: 5},
{ProductId: results.products[(i * 2) + 0].id, value: 10},
{ProductId: results.products[(i * 2) + 1].id, value: 5},
{ProductId: results.products[(i * 2) + 1].id, value: 10},
{ProductId: results.products[(i * 2) + 1].id, value: 15},
{ProductId: results.products[(i * 2) + 1].id, value: 20}
]).done(callback)
}]
}, callback)
},
function (err) {
expect(err).not.to.be.ok
AccUser.findAll({
include: [
{model: GroupMember, as: 'Memberships', include: [
Group,
Rank
]},
{model: Product, include: [
Tag,
{model: Tag, as: 'Category'},
Price
]}
],
order: [
[AccUser.rawAttributes.id, 'ASC']
]
}).done(function (err, users) {
expect(err).not.to.be.ok
users.forEach(function (user, i) {
expect(user.memberships).to.be.ok
user.memberships.sort(sortById)
expect(user.memberships.length).to.equal(2)
expect(user.memberships[0].group.name).to.equal('Developers')
expect(user.memberships[0].rank.canRemove).to.equal(1)
expect(user.memberships[1].group.name).to.equal('Designers')
expect(user.memberships[1].rank.canRemove).to.equal(0)
user.products.sort(sortById)
expect(user.products.length).to.equal(2)
expect(user.products[0].tags.length).to.equal(2)
expect(user.products[1].tags.length).to.equal(1)
expect(user.products[0].category).to.be.ok
expect(user.products[1].category).not.to.be.ok
expect(user.products[0].prices.length).to.equal(2)
expect(user.products[1].prices.length).to.equal(4)
done()
})
})
}
)
}]
}, done)
})
})
})
})
it('should support many levels of belongsTo', function (done) {
var A = this.sequelize.define('A', {}, {schema: "account"})
, B = this.sequelize.define('B', {}, {schema: "account"})
, C = this.sequelize.define('C', {}, {schema: "account"})
, D = this.sequelize.define('D', {}, {schema: "account"})
, E = this.sequelize.define('E', {}, {schema: "account"})
, F = this.sequelize.define('F', {}, {schema: "account"})
, G = this.sequelize.define('G', {}, {schema: "account"})
, H = this.sequelize.define('H', {}, {schema: "account"})
A.belongsTo(B)
B.belongsTo(C)
C.belongsTo(D)
D.belongsTo(E)
E.belongsTo(F)
F.belongsTo(G)
G.belongsTo(H)
var b, singles = [
B,
C,
D,
E,
F,
G,
H
]
this.sequelize.sync().done(function () {
async.auto({
as: function (callback) {
A.bulkCreate([
{},
{},
{},
{},
{},
{},
{},
{}
]).done(function () {
A.findAll().done(callback)
})
},
singleChain: function (callback) {
var previousInstance
, previousModel
async.eachSeries(singles, function (model, callback, i) {
model.create({}).done(function (err, instance) {
if (previousInstance) {
previousInstance["set"+model.name](instance).done(function () {
previousInstance = instance
callback()
})
} else {
previousInstance = b = instance
callback()
}
})
}, callback)
},
abs: ['as', 'singleChain', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
results.as.forEach(function (a) {
chainer.add(a.setB(b))
})
chainer.run().done(callback)
}]
}, function () {
A.findAll({
include: [
{model: B, include: [
{model: C, include: [
{model: D, include: [
{model: E, include: [
{model: F, include: [
{model: G, include: [
{model: H}
]}
]}
]}
]}
]}
]}
]
}).done(function (err, as) {
expect(err).not.to.be.ok
expect(as.length).to.be.ok
as.forEach(function (a) {
expect(a.b.c.d.e.f.g.h).to.be.ok
})
done()
})
})
})
})
it('should support ordering with only belongsTo includes', function(done) {
var User = this.sequelize.define('SpecialUser', {}, {schema: "account"})
, Item = this.sequelize.define('Item', {'test': DataTypes.STRING}, {schema: "account"})
, Order = this.sequelize.define('Order', {'position': DataTypes.INTEGER}, {schema: "account"})
User.belongsTo(Item, {'as': 'itemA', foreignKey: 'itemA_id'})
User.belongsTo(Item, {'as': 'itemB', foreignKey: 'itemB_id'})
User.belongsTo(Order)
this.sequelize.sync().done(function() {
async.auto({
users: function(callback) {
User.bulkCreate([{}, {}, {}]).done(function() {
User.findAll().done(callback)
})
},
items: function(callback) {
Item.bulkCreate([
{'test': 'abc'},
{'test': 'def'},
{'test': 'ghi'},
{'test': 'jkl'}
]).done(function() {
Item.findAll({order: ['id']}).done(callback)
})
},
orders: function(callback) {
Order.bulkCreate([
{'position': 2},
{'position': 3},
{'position': 1}
]).done(function() {
Order.findAll({order: ['id']}).done(callback)
})
},
associate: ['users', 'items', 'orders', function(callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
var user1 = results.users[0]
var user2 = results.users[1]
var user3 = results.users[2]
var item1 = results.items[0]
var item2 = results.items[1]
var item3 = results.items[2]
var item4 = results.items[3]
var order1 = results.orders[0]
var order2 = results.orders[1]
var order3 = results.orders[2]
chainer.add(user1.setItemA(item1))
chainer.add(user1.setItemB(item2))
chainer.add(user1.setOrder(order3))
chainer.add(user2.setItemA(item3))
chainer.add(user2.setItemB(item4))
chainer.add(user2.setOrder(order2))
chainer.add(user3.setItemA(item1))
chainer.add(user3.setItemB(item4))
chainer.add(user3.setOrder(order1))
chainer.run().done(callback)
}]
}, function() {
User.findAll({
'where': {'itemA.test': 'abc'},
'include': [
{'model': Item, 'as': 'itemA'},
{'model': Item, 'as': 'itemB'},
Order],
'order': ['Order.position']
}).done(function(err, as) {
expect(err).not.to.be.ok
expect(as.length).to.eql(2)
expect(as[0].itemA.test).to.eql('abc')
expect(as[1].itemA.test).to.eql('abc')
expect(as[0].order.position).to.eql(1)
expect(as[1].order.position).to.eql(2)
done()
})
})
})
})
it('should include attributes from through models', function (done) {
var Product = this.sequelize.define('Product', {
title: DataTypes.STRING
}, {schema: "account"})
, Tag = this.sequelize.define('Tag', {
name: DataTypes.STRING
}, {schema: "account"})
, ProductTag = this.sequelize.define('ProductTag', {
priority: DataTypes.INTEGER
}, {schema: "account"})
Product.hasMany(Tag, {through: ProductTag})
Tag.hasMany(Product, {through: ProductTag})
this.sequelize.sync({force: true}).done(function () {
async.auto({
products: function (callback) {
Product.bulkCreate([
{title: 'Chair'},
{title: 'Desk'},
{title: 'Dress'}
]).done(function () {
Product.findAll().done(callback)
})
},
tags: function(callback) {
Tag.bulkCreate([
{name: 'A'},
{name: 'B'},
{name: 'C'}
]).done(function () {
Tag.findAll().done(callback)
})
},
productTags: ['products', 'tags', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.products[0].addTag(results.tags[0], {priority: 1}))
chainer.add(results.products[0].addTag(results.tags[1], {priority: 2}))
chainer.add(results.products[1].addTag(results.tags[1], {priority: 1}))
chainer.add(results.products[2].addTag(results.tags[0], {priority: 3}))
chainer.add(results.products[2].addTag(results.tags[1], {priority: 1}))
chainer.add(results.products[2].addTag(results.tags[2], {priority: 2}))
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
Product.findAll({
include: [
{model: Tag}
],
order: [
['id', 'ASC'],
['Tags.id', 'ASC']
]
}).done(function (err, products) {
expect(err).not.to.be.ok
expect(products[0].tags[0].productTag.priority).to.equal(1)
expect(products[0].tags[1].productTag.priority).to.equal(2)
expect(products[1].tags[0].productTag.priority).to.equal(1)
expect(products[2].tags[0].productTag.priority).to.equal(3)
expect(products[2].tags[1].productTag.priority).to.equal(1)
expect(products[2].tags[2].productTag.priority).to.equal(2)
done()
})
})
})
})
it('should support a required belongsTo include', function (done) {
var User = this.sequelize.define('User', {}, {schema: "account"})
, Group = this.sequelize.define('Group', {}, {schema: "account"})
User.belongsTo(Group)
this.sequelize.sync({force: true}).done(function () {
async.auto({
groups: function (callback) {
Group.bulkCreate([{}, {}]).done(function () {
Group.findAll().done(callback)
})
},
users: function (callback) {
User.bulkCreate([{}, {}, {}]).done(function () {
User.findAll().done(callback)
})
},
userGroups: ['users', 'groups', function (callback, results) {
results.users[2].setGroup(results.groups[1]).done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: Group, required: true}
]
}).done(function (err, users) {
expect(err).not.to.be.ok
expect(users.length).to.equal(1)
expect(users[0].group).to.be.ok
done()
})
})
})
})
it('should be possible to extend the on clause with a where option on a belongsTo include', function (done) {
var User = this.sequelize.define('User', {}, {schema: "account"})
, Group = this.sequelize.define('Group', {
name: DataTypes.STRING
}, {schema: "account"})
User.belongsTo(Group)
this.sequelize.sync({force: true}).done(function () {
async.auto({
groups: function (callback) {
Group.bulkCreate([
{name: 'A'},
{name: 'B'}
]).done(function () {
Group.findAll().done(callback)
})
},
users: function (callback) {
User.bulkCreate([{}, {}]).done(function () {
User.findAll().done(callback)
})
},
userGroups: ['users', 'groups', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.users[0].setGroup(results.groups[1]))
chainer.add(results.users[1].setGroup(results.groups[0]))
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: Group, where: {name: 'A'}}
]
}).done(function (err, users) {
expect(err).not.to.be.ok
expect(users.length).to.equal(1)
expect(users[0].group).to.be.ok
expect(users[0].group.name).to.equal('A')
done()
})
})
})
})
it('should be possible to extend the on clause with a where option on a belongsTo include', function (done) {
var User = this.sequelize.define('User', {}, {schema: "account"})
, Group = this.sequelize.define('Group', {
name: DataTypes.STRING
}, {schema: "account"})
User.belongsTo(Group)
this.sequelize.sync({force: true}).done(function () {
async.auto({
groups: function (callback) {
Group.bulkCreate([
{name: 'A'},
{name: 'B'}
]).done(function () {
Group.findAll().done(callback)
})
},
users: function (callback) {
User.bulkCreate([{}, {}]).done(function () {
User.findAll().done(callback)
})
},
userGroups: ['users', 'groups', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.users[0].setGroup(results.groups[1]))
chainer.add(results.users[1].setGroup(results.groups[0]))
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: Group, required: true}
]
}).done(function (err, users) {
expect(err).not.to.be.ok
users.forEach(function (user) {
expect(user.group).to.be.ok
})
done()
})
})
})
})
it('should be possible to define a belongsTo include as required with child hasMany with limit', function (done) {
var User = this.sequelize.define('User', {}, {schema: "account"}) , Group = this.sequelize.define('Group', {
name: DataTypes.STRING
}, {schema: "account"})
, Category = this.sequelize.define('Category', {
category: DataTypes.STRING
}, {schema: "account"})
User.belongsTo(Group)
Group.hasMany(Category)
this.sequelize.sync({force: true}).done(function () {
async.auto({
groups: function (callback) {
Group.bulkCreate([
{name: 'A'},
{name: 'B'}
]).done(function () {
Group.findAll().done(callback)
})
},
users: function (callback) {
User.bulkCreate([{}, {}]).done(function () {
User.findAll().done(callback)
})
},
categories: function (callback) {
Category.bulkCreate([{}, {}]).done(function () {
Category.findAll().done(callback)
})
},
userGroups: ['users', 'groups', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.users[0].setGroup(results.groups[1]))
chainer.add(results.users[1].setGroup(results.groups[0]))
chainer.run().done(callback)
}],
groupCategories: ['groups', 'categories', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
results.groups.forEach(function (group) {
chainer.add(group.setCategories(results.categories))
})
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: Group, required: true, include: [
{model: Category}
]}
],
limit: 1
}).done(function (err, users) {
expect(err).not.to.be.ok
expect(users.length).to.equal(1)
users.forEach(function (user) {
expect(user.group).to.be.ok
expect(user.group.categories).to.be.ok
})
done()
})
})
})
})
it('should be possible to define a belongsTo include as required with child hasMany with limit and aliases', function (done) {
var User = this.sequelize.define('User', {}, {schema: "account"})
, Group = this.sequelize.define('Group', {
name: DataTypes.STRING
}, {schema: "account"})
, Category = this.sequelize.define('Category', {
category: DataTypes.STRING
}, {schema: "account"})
User.belongsTo(Group, {as: 'Team'})
Group.hasMany(Category, {as: 'Tags'})
this.sequelize.sync({force: true}).done(function () {
async.auto({
groups: function (callback) {
Group.bulkCreate([
{name: 'A'},
{name: 'B'}
]).done(function () {
Group.findAll().done(callback)
})
},
users: function (callback) {
User.bulkCreate([{}, {}]).done(function () {
User.findAll().done(callback)
})
},
categories: function (callback) {
Category.bulkCreate([{}, {}]).done(function () {
Category.findAll().done(callback)
})
},
userGroups: ['users', 'groups', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.users[0].setTeam(results.groups[1]))
chainer.add(results.users[1].setTeam(results.groups[0]))
chainer.run().done(callback)
}],
groupCategories: ['groups', 'categories', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
results.groups.forEach(function (group) {
chainer.add(group.setTags(results.categories))
})
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: Group, required: true, as: 'Team', include: [
{model: Category, as: 'Tags'}
]}
],
limit: 1
}).done(function (err, users) {
expect(err).not.to.be.ok
expect(users.length).to.equal(1)
users.forEach(function (user) {
expect(user.team).to.be.ok
expect(user.team.tags).to.be.ok
})
done()
})
})
})
})
it('should be possible to define a belongsTo include as required with child hasMany which is not required with limit', function (done) {
var User = this.sequelize.define('User', {}, {schema: "account"})
, Group = this.sequelize.define('Group', {
name: DataTypes.STRING
}, {schema: "account"})
, Category = this.sequelize.define('Category', {
category: DataTypes.STRING
}, {schema: "account"})
User.belongsTo(Group)
Group.hasMany(Category)
this.sequelize.sync({force: true}).done(function () {
async.auto({
groups: function (callback) {
Group.bulkCreate([
{name: 'A'},
{name: 'B'}
]).done(function () {
Group.findAll().done(callback)
})
},
users: function (callback) {
User.bulkCreate([{}, {}]).done(function () {
User.findAll().done(callback)
})
},
categories: function (callback) {
Category.bulkCreate([{}, {}]).done(function () {
Category.findAll().done(callback)
})
},
userGroups: ['users', 'groups', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.users[0].setGroup(results.groups[1]))
chainer.add(results.users[1].setGroup(results.groups[0]))
chainer.run().done(callback)
}],
groupCategories: ['groups', 'categories', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
results.groups.forEach(function (group) {
chainer.add(group.setCategories(results.categories))
})
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: Group, required: true, include: [
{model: Category, required: false}
]}
],
limit: 1
}).done(function (err, users) {
expect(err).not.to.be.ok
expect(users.length).to.equal(1)
users.forEach(function (user) {
expect(user.group).to.be.ok
expect(user.group.categories).to.be.ok
})
done()
})
})
})
})
it('should be possible to extend the on clause with a where option on a hasOne include', function (done) {
var User = this.sequelize.define('User', {}, {schema: "account"})
, Project = this.sequelize.define('Project', {
title: DataTypes.STRING
}, {schema: "account"})
User.hasOne(Project, {as: 'LeaderOf'})
this.sequelize.sync({force: true}).done(function () {
async.auto({
projects: function (callback) {
Project.bulkCreate([
{title: 'Alpha'},
{title: 'Beta'}
]).done(function () {
Project.findAll().done(callback)
})
},
users: function (callback) {
User.bulkCreate([{}, {}]).done(function () {
User.findAll().done(callback)
})
},
userProjects: ['users', 'projects', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.users[1].setLeaderOf(results.projects[1]))
chainer.add(results.users[0].setLeaderOf(results.projects[0]))
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: Project, as: 'LeaderOf', where: {title: 'Beta'}}
]
}).done(function (err, users) {
expect(err).not.to.be.ok
expect(users.length).to.equal(1)
expect(users[0].leaderOf).to.be.ok
expect(users[0].leaderOf.title).to.equal('Beta')
done()
})
})
})
})
it('should be possible to extend the on clause with a where option on a hasMany include with a through model', function (done) {
var Product = this.sequelize.define('Product', {
title: DataTypes.STRING
}, {schema: "account"})
, Tag = this.sequelize.define('Tag', {
name: DataTypes.STRING
}, {schema: "account"})
, ProductTag = this.sequelize.define('ProductTag', {
priority: DataTypes.INTEGER
}, {schema: "account"})
Product.hasMany(Tag, {through: ProductTag})
Tag.hasMany(Product, {through: ProductTag})
this.sequelize.sync({force: true}).done(function () {
async.auto({
products: function (callback) {
Product.bulkCreate([
{title: 'Chair'},
{title: 'Desk'},
{title: 'Dress'}
]).done(function () {
Product.findAll().done(callback)
})
},
tags: function(callback) {
Tag.bulkCreate([
{name: 'A'},
{name: 'B'},
{name: 'C'}
]).done(function () {
Tag.findAll().done(callback)
})
},
productTags: ['products', 'tags', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.products[0].addTag(results.tags[0], {priority: 1}))
chainer.add(results.products[0].addTag(results.tags[1], {priority: 2}))
chainer.add(results.products[1].addTag(results.tags[1], {priority: 1}))
chainer.add(results.products[2].addTag(results.tags[0], {priority: 3}))
chainer.add(results.products[2].addTag(results.tags[1], {priority: 1}))
chainer.add(results.products[2].addTag(results.tags[2], {priority: 2}))
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
Product.findAll({
include: [
{model: Tag, where: {name: 'C'}}
]
}).done(function (err, products) {
expect(err).not.to.be.ok
expect(products.length).to.equal(1)
expect(products[0].tags.length).to.equal(1)
done()
})
})
})
})
it('should be possible to extend the on clause with a where option on nested includes', function (done) {
var User = this.sequelize.define('User', {
name: DataTypes.STRING
}, {schema: "account"})
, Product = this.sequelize.define('Product', {
title: DataTypes.STRING
}, {schema: "account"})
, Tag = this.sequelize.define('Tag', {
name: DataTypes.STRING
}, {schema: "account"})
, Price = this.sequelize.define('Price', {
value: DataTypes.FLOAT
}, {schema: "account"})
, Customer = this.sequelize.define('Customer', {
name: DataTypes.STRING
}, {schema: "account"})
, Group = this.sequelize.define('Group', {
name: DataTypes.STRING
}, {schema: "account"})
, GroupMember = this.sequelize.define('GroupMember', {
}, {schema: "account"})
, Rank = this.sequelize.define('Rank', {
name: DataTypes.STRING,
canInvite: {
type: DataTypes.INTEGER,
defaultValue: 0
},
canRemove: {
type: DataTypes.INTEGER,
defaultValue: 0
}
}, {schema: "account"})
User.hasMany(Product)
Product.belongsTo(User)
Product.hasMany(Tag)
Tag.hasMany(Product)
Product.belongsTo(Tag, {as: 'Category'})
Product.hasMany(Price)
Price.belongsTo(Product)
User.hasMany(GroupMember, {as: 'Memberships'})
GroupMember.belongsTo(User)
GroupMember.belongsTo(Rank)
GroupMember.belongsTo(Group)
Group.hasMany(GroupMember, {as: 'Memberships'})
this.sequelize.sync({force: true}).done(function () {
var count = 4
, i = -1
async.auto({
groups: function(callback) {
Group.bulkCreate([
{name: 'Developers'},
{name: 'Designers'}
]).done(function () {
Group.findAll().done(callback)
})
},
ranks: function(callback) {
Rank.bulkCreate([
{name: 'Admin', canInvite: 1, canRemove: 1},
{name: 'Member', canInvite: 1, canRemove: 0}
]).done(function () {
Rank.findAll().done(callback)
})
},
tags: function(callback) {
Tag.bulkCreate([
{name: 'A'},
{name: 'B'},
{name: 'C'}
]).done(function () {
Tag.findAll().done(callback)
})
},
loop: ['groups', 'ranks', 'tags', function (done, results) {
var groups = results.groups
, ranks = results.ranks
, tags = results.tags
async.whilst(
function () { return i < count; },
function (callback) {
i++
async.auto({
user: function (callback) {
User.create({name: 'FooBarzz'}).done(callback)
},
memberships: ['user', function (callback, results) {
GroupMember.bulkCreate([
{UserId: results.user.id, GroupId: groups[0].id, RankId: ranks[0].id},
{UserId: results.user.id, GroupId: groups[1].id, RankId: ranks[1].id}
]).done(callback)
}],
products: function (callback) {
Product.bulkCreate([
{title: 'Chair'},
{title: 'Desk'}
]).done(function () {
Product.findAll().done(callback)
})
},
userProducts: ['user', 'products', function (callback, results) {
results.user.setProducts([
results.products[(i * 2)+0],
results.products[(i * 2)+1]
]).done(callback)
}],
productTags: ['products', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.products[(i * 2) + 0].setTags([
tags[0],
tags[2]
]))
chainer.add(results.products[(i * 2) + 1].setTags([
tags[1]
]))
chainer.add(results.products[(i * 2) + 0].setCategory(tags[1]))
chainer.run().done(callback)
}],
prices: ['products', function (callback, results) {
Price.bulkCreate([
{ProductId: results.products[(i * 2) + 0].id, value: 5},
{ProductId: results.products[(i * 2) + 0].id, value: 10},
{ProductId: results.products[(i * 2) + 1].id, value: 5},
{ProductId: results.products[(i * 2) + 1].id, value: 10},
{ProductId: results.products[(i * 2) + 1].id, value: 15},
{ProductId: results.products[(i * 2) + 1].id, value: 20}
]).done(callback)
}]
}, callback)
},
function (err) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: GroupMember, as: 'Memberships', include: [
Group,
{model: Rank, where: {name: 'Admin'}}
]},
{model: Product, include: [
Tag,
{model: Tag, as: 'Category'},
{model: Price, where: {
value: {
gt: 15
}
}}
]}
],
order: 'id ASC'
}).done(function (err, users) {
expect(err).not.to.be.ok
users.forEach(function (user) {
expect(user.memberships.length).to.equal(1)
expect(user.memberships[0].rank.name).to.equal('Admin')
expect(user.products.length).to.equal(1)
expect(user.products[0].prices.length).to.equal(1)
})
done()
})
}
)
}]
}, done)
})
})
it('should be possible to use limit and a where with a belongsTo include', function (done) {
var User = this.sequelize.define('User', {}, {schema: "account"})
, Group = this.sequelize.define('Group', {
name: DataTypes.STRING
}, {schema: "account"})
User.belongsTo(Group)
this.sequelize.sync({force: true}).done(function () {
async.auto({
groups: function (callback) {
Group.bulkCreate([
{name: 'A'},
{name: 'B'},
]).done(function () {
Group.findAll().done(callback)
})
},
users: function (callback) {
User.bulkCreate([{}, {}, {}, {}]).done(function () {
User.findAll().done(callback)
})
},
userGroups: ['users', 'groups', function (callback, results) {
var chainer = new Sequelize.Utils.QueryChainer()
chainer.add(results.users[0].setGroup(results.groups[0]))
chainer.add(results.users[1].setGroup(results.groups[0]))
chainer.add(results.users[2].setGroup(results.groups[0]))
chainer.add(results.users[3].setGroup(results.groups[1]))
chainer.run().done(callback)
}]
}, function (err, results) {
expect(err).not.to.be.ok
User.findAll({
include: [
{model: Group, where: {name: 'A'}}
],
limit: 2
}).done(function (err, users) {
expect(err).not.to.be.ok
expect(users.length).to.equal(2)
users.forEach(function (user) {
expect(user.group.name).to.equal('A')
})
done()
})
})
})
})
it('should be possible use limit, attributes and a where on a belongsTo with additional hasMany includes', function (done) {
var self = this
this.fixtureA(function () {
self.models.Product.findAll({
attributes: ['title'],
include: [
{model: self.models.Company, where: {name: 'NYSE'}},
{model: self.models.Tag},
{model: self.models.Price}
],
limit: 3,
order: [
[self.models.Product.name+'.id', 'ASC']
]
}).done(function (err, products) {
expect(err).not.to.be.ok
expect(products.length).to.equal(3)
products.forEach(function (product) {
expect(product.company.name).to.equal('NYSE')
expect(product.tags.length).to.be.ok
expect(product.prices.length).to.be.ok
})
done()
})
})
})
it('should be possible to use limit and a where on a hasMany with additional includes', function (done) {
var self = this
this.fixtureA(function () {
self.models.Product.findAll({
include: [
{model: self.models.Company},
{model: self.models.Tag},
{model: self.models.Price, where: {
value: {gt: 5}
}}
],
limit: 6,
order: 'id ASC'
}).done(function (err, products) {
expect(err).not.to.be.ok
expect(products.length).to.equal(6)
products.forEach(function (product) {
expect(product.tags.length).to.be.ok
expect(product.prices.length).to.be.ok
product.prices.forEach(function (price) {
expect(price.value).to.be.above(5)
})
})
done()
})
})
})
it('should be possible to use limit and a where on a hasMany with a through model with additional includes', function (done) {
var self = this
this.fixtureA(function () {
self.models.Product.findAll({
include: [
{model: self.models.Company},
{model: self.models.Tag, where: {name: ['A', 'B','C']}},
{model: self.models.Price}
],
limit: 10,
order: 'id ASC'
}).done(function (err, products) {
expect(err).not.to.be.ok
expect(products.length).to.equal(10)
products.forEach(function (product) {
expect(product.tags.length).to.be.ok
expect(product.prices.length).to.be.ok
product.tags.forEach(function (tag) {
expect(['A', 'B', 'C']).to.include(tag.name)
})
})
done()
})
})
})
xit('should support including date fields, with the correct timeszone', function (done) {
var User = this.sequelize.define('user', {
dateField: Sequelize.DATE
}, {timestamps: false, schema: "account"})
, Group = this.sequelize.define('group', {
dateField: Sequelize.DATE
}, {timestamps: false, schema: "account"})
User.hasMany(Group)
Group.hasMany(User)
this.sequelize.sync().success(function () {
User.create({ dateField: Date.UTC(2014, 1, 20) }).success(function (user) {
Group.create({ dateField: Date.UTC(2014, 1, 20) }).success(function (group) {
user.addGroup(group).success(function () {
User.findAll({
where: {
id: user.id
},
include: [Group]
}).success(function (users) {
expect(users[0].dateField.getTime()).to.equal(Date.UTC(2014, 1, 20))
expect(users[0].groups[0].dateField.getTime()).to.equal(Date.UTC(2014, 1, 20))
done()
})
})
})
})
})
})
})
})
\ No newline at end of file
...@@ -29,7 +29,7 @@ if (dialect.match(/^postgres/)) { ...@@ -29,7 +29,7 @@ if (dialect.match(/^postgres/)) {
it('should be able to search within an array', function(done) { it('should be able to search within an array', function(done) {
this.User.all({where: {email: ['hello', 'world']}}).on('sql', function(sql) { this.User.all({where: {email: ['hello', 'world']}}).on('sql', function(sql) {
expect(sql).to.equal('SELECT * FROM "Users" WHERE "Users"."email" && ARRAY[\'hello\',\'world\']::TEXT[];') expect(sql).to.equal('SELECT * FROM "Users" AS "User" WHERE "User"."email" && ARRAY[\'hello\',\'world\']::TEXT[];')
done() done()
}) })
}) })
......
...@@ -158,7 +158,7 @@ if (dialect.match(/^postgres/)) { ...@@ -158,7 +158,7 @@ if (dialect.match(/^postgres/)) {
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, },
{ {
arguments: ['mySchema.myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}], arguments: [{schema: 'mySchema', tableName: 'myTable'}, {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS mySchema.myTable (title VARCHAR(255), name VARCHAR(255));", expectation: "CREATE TABLE IF NOT EXISTS mySchema.myTable (title VARCHAR(255), name VARCHAR(255));",
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, },
...@@ -586,13 +586,13 @@ if (dialect.match(/^postgres/)) { ...@@ -586,13 +586,13 @@ if (dialect.match(/^postgres/)) {
expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;", expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {omitNull: true}} // Note: As above context: {options: {omitNull: true}} // Note: As above
}, { }, {
arguments: ['mySchema.myTable', [{name: 'foo'}, {name: 'bar'}]], arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'),('bar') RETURNING *;" expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'),('bar') RETURNING *;"
}, { }, {
arguments: ['mySchema.myTable', [{name: JSON.stringify({info: 'Look ma a " quote'})}, {name: JSON.stringify({info: 'Look ma another " quote'})}]], arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: JSON.stringify({info: 'Look ma a " quote'})}, {name: JSON.stringify({info: 'Look ma another " quote'})}]],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}') RETURNING *;" expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}') RETURNING *;"
}, { }, {
arguments: ['mySchema.myTable', [{name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'bar'}]], arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'bar'}]],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar') RETURNING *;" expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar') RETURNING *;"
}, },
...@@ -630,15 +630,15 @@ if (dialect.match(/^postgres/)) { ...@@ -630,15 +630,15 @@ if (dialect.match(/^postgres/)) {
expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;", expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {omitNull: true, quoteIdentifiers: false}} // Note: As above context: {options: {omitNull: true, quoteIdentifiers: false}} // Note: As above
}, { }, {
arguments: ['mySchema.myTable', [{name: 'foo'}, {name: 'bar'}]], arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'),('bar') RETURNING *;", expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'),('bar') RETURNING *;",
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, { }, {
arguments: ['mySchema.myTable', [{name: JSON.stringify({info: 'Look ma a " quote'})}, {name: JSON.stringify({info: 'Look ma another " quote'})}]], arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: JSON.stringify({info: 'Look ma a " quote'})}, {name: JSON.stringify({info: 'Look ma another " quote'})}]],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}') RETURNING *;", expectation: "INSERT INTO mySchema.myTable (name) VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}') RETURNING *;",
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, { }, {
arguments: ['mySchema.myTable', [{name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'bar'}]], arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'bar'}]],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar') RETURNING *;", expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar') RETURNING *;",
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
} }
...@@ -737,11 +737,11 @@ if (dialect.match(/^postgres/)) { ...@@ -737,11 +737,11 @@ if (dialect.match(/^postgres/)) {
expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *", expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *",
context: {options: {omitNull: true, quoteIdentifiers: false}}, context: {options: {omitNull: true, quoteIdentifiers: false}},
}, { }, {
arguments: ['mySchema.myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}], arguments: [{schema: 'mySchema', tableName: 'myTable'}, {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}],
expectation: "UPDATE mySchema.myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2 RETURNING *", expectation: "UPDATE mySchema.myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2 RETURNING *",
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
}, { }, {
arguments: ['mySchema.myTable', {name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'foo'}], arguments: [{schema: 'mySchema', tableName: 'myTable'}, {name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'foo'}],
expectation: "UPDATE mySchema.myTable SET name='foo'';DROP TABLE mySchema.myTable;' WHERE name='foo' RETURNING *", expectation: "UPDATE mySchema.myTable SET name='foo'';DROP TABLE mySchema.myTable;' WHERE name='foo' RETURNING *",
context: {options: {quoteIdentifiers: false}} context: {options: {quoteIdentifiers: false}}
} }
......
...@@ -227,7 +227,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () { ...@@ -227,7 +227,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
.then(function() { .then(function() {
return Book return Book
.find({ .find({
where: (dialect === 'postgres' ? '"Books"."id"=' : '`Books`.`id`=') + book.id, where: (dialect === 'postgres' ? '"Book"."id"=' : '`Book`.`id`=') + book.id,
include: [Page] include: [Page]
}) })
.then(function (leBook) { .then(function (leBook) {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!