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

Commit 62ad873a by Sascha Depold

Merge branch 'refactorings/eager_loading'

2 parents 6c06ac2a 7ef6a12d
...@@ -19,7 +19,5 @@ env: ...@@ -19,7 +19,5 @@ env:
language: node_js language: node_js
node_js: node_js:
# - 0.6
- 0.8 - 0.8
# - 0.9
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
- [BUG] fixed updateAttributes for models/tables without primary key (thanks to durango) - [BUG] fixed updateAttributes for models/tables without primary key (thanks to durango)
- [BUG] fixed the location of the foreign key when using belongsTo (thanks to ricardograca) - [BUG] fixed the location of the foreign key when using belongsTo (thanks to ricardograca)
- [BUG] don't return timestamps if only specific attributes have been seleceted (thanks to ricardograca) - [BUG] don't return timestamps if only specific attributes have been seleceted (thanks to ricardograca)
- [FEATURE] added association prefetching for find and findAll - [FEATURE] added association prefetching /eager loading for find and findAll. #465
- [FEATURE] it's now possible to use callbacks of async functions inside migrations (thanks to mphilpot) - [FEATURE] it's now possible to use callbacks of async functions inside migrations (thanks to mphilpot)
- [FEATURE] improved comfort of sequelize.query. just pass an sql string to it and wait for the result - [FEATURE] improved comfort of sequelize.query. just pass an sql string to it and wait for the result
- [FEATURE] Migrations now understand NODE_ENV (thanks to gavri) - [FEATURE] Migrations now understand NODE_ENV (thanks to gavri)
......
/**
The entry point.
@module sequelize
**/
module.exports = require("./lib/sequelize") module.exports = require("./lib/sequelize")
...@@ -19,11 +19,11 @@ Mixin.hasOne = function(associatedDAO, options) { ...@@ -19,11 +19,11 @@ Mixin.hasOne = function(associatedDAO, options) {
Mixin.belongsTo = function(associatedDAO, options) { Mixin.belongsTo = function(associatedDAO, options) {
// the id is in this table // the id is in this table
var association = new BelongsTo(this, associatedDAO, Utils._.extend((options||{}), this.options)) var association = new BelongsTo(this, associatedDAO, Utils._.extend((options || {}), this.options))
this.associations[association.associationAccessor] = association.injectAttributes() this.associations[association.associationAccessor] = association.injectAttributes()
association.injectGetter(this.DAO.prototype); association.injectGetter(this.DAO.prototype)
association.injectSetter(this.DAO.prototype); association.injectSetter(this.DAO.prototype)
return this return this
} }
...@@ -33,8 +33,8 @@ Mixin.hasMany = function(associatedDAO, options) { ...@@ -33,8 +33,8 @@ Mixin.hasMany = function(associatedDAO, options) {
var association = new HasMany(this, associatedDAO, Utils._.extend((options||{}), this.options)) var association = new HasMany(this, associatedDAO, Utils._.extend((options||{}), this.options))
this.associations[association.associationAccessor] = association.injectAttributes() this.associations[association.associationAccessor] = association.injectAttributes()
association.injectGetter(this.DAO.prototype); association.injectGetter(this.DAO.prototype)
association.injectSetter(this.DAO.prototype); association.injectSetter(this.DAO.prototype)
return this return this
} }
......
...@@ -143,25 +143,25 @@ module.exports = (function() { ...@@ -143,25 +143,25 @@ module.exports = (function() {
var hasJoin = false var hasJoin = false
var options = Utils._.clone(options) var options = Utils._.clone(options)
if ((typeof options === 'object') && (options.hasOwnProperty('include'))) { if (typeof options === 'object') {
var includes = options.include
hasJoin = true hasJoin = true
options.include = {}
includes.forEach(function(daoName) { if (options.hasOwnProperty('include')) {
options.include[daoName] = this.daoFactoryManager.getDAO(daoName) hasJoin = true
if (!options.include[daoName]) { options.include = options.include.map(function(include) {
options.include[daoName] = this.getAssociationByAlias(daoName).target return validateIncludedElement.call(this, include)
}
}.bind(this)) }.bind(this))
}
// whereCollection is used for non-primary key updates // whereCollection is used for non-primary key updates
this.options.whereCollection = options.where || null this.options.whereCollection = options.where || null
} }
return this.QueryInterface.select(this, this.tableName, options, { type: 'SELECT', hasJoin: hasJoin }) return this.QueryInterface.select(this, this.tableName, options, {
type: 'SELECT',
hasJoin: hasJoin
})
} }
//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
...@@ -175,8 +175,16 @@ module.exports = (function() { ...@@ -175,8 +175,16 @@ module.exports = (function() {
return this.QueryInterface.select(this, [this.tableName, joinTableName], optcpy, { type: 'SELECT' }) return this.QueryInterface.select(this, [this.tableName, joinTableName], optcpy, { type: 'SELECT' })
} }
/**
* Search for an instance.
*
* @param {Object} options Options to describe the scope of the search.
* @param {Array} include A list of associations which shall get eagerly loaded. Supported is either { include: [ DaoFactory1, DaoFactory2, ...] } or { include: [ { daoFactory: DaoFactory1, as: 'Alias' } ] }.
* @return {Object} A promise which fires `success`, `error`, `complete` and `sql`.
*/
DAOFactory.prototype.find = function(options) { DAOFactory.prototype.find = function(options) {
var hasJoin = false var hasJoin = false
// no options defined? // no options defined?
// return an emitter which emits null // return an emitter which emits null
if ([null, undefined].indexOf(options) !== -1) { if ([null, undefined].indexOf(options) !== -1) {
...@@ -210,20 +218,13 @@ module.exports = (function() { ...@@ -210,20 +218,13 @@ module.exports = (function() {
options = { where: parsedId } options = { where: parsedId }
} else if (typeof options === 'object') { } else if (typeof options === 'object') {
var options = Utils._.clone(options) options = Utils._.clone(options)
var includes
if (options.hasOwnProperty('include')) { if (options.hasOwnProperty('include')) {
hasJoin = true hasJoin = true
includes = options.include
options.include = {}
includes.forEach(function(daoName) { options.include = options.include.map(function(include) {
options.include[daoName] = this.daoFactoryManager.getDAO(daoName) return validateIncludedElement.call(this, include)
if (!options.include[daoName]) {
options.include[daoName] = this.getAssociationByAlias(daoName).target
}
}.bind(this)) }.bind(this))
} }
...@@ -233,7 +234,11 @@ module.exports = (function() { ...@@ -233,7 +234,11 @@ module.exports = (function() {
options.limit = 1 options.limit = 1
return this.QueryInterface.select(this, this.tableName, options, { plain: true, type: 'SELECT', hasJoin: hasJoin }) return this.QueryInterface.select(this, this.tableName, options, {
plain: true,
type: 'SELECT',
hasJoin: hasJoin
})
} }
DAOFactory.prototype.count = function(options) { DAOFactory.prototype.count = function(options) {
...@@ -260,7 +265,7 @@ module.exports = (function() { ...@@ -260,7 +265,7 @@ module.exports = (function() {
} }
DAOFactory.prototype.build = function(values, options) { DAOFactory.prototype.build = function(values, options) {
options = options || {isNewRecord: true} options = options || { isNewRecord: true }
var self = this var self = this
, instance = new this.DAO(values, this.options, options.isNewRecord) , instance = new this.DAO(values, this.options, options.isNewRecord)
...@@ -283,7 +288,7 @@ module.exports = (function() { ...@@ -283,7 +288,7 @@ module.exports = (function() {
}).success(function (instance) { }).success(function (instance) {
if (instance === null) { if (instance === null) {
for (var attrname in defaults) { for (var attrname in defaults) {
params[attrname] = defaults[attrname]; params[attrname] = defaults[attrname]
} }
self.create(params) self.create(params)
...@@ -292,7 +297,7 @@ module.exports = (function() { ...@@ -292,7 +297,7 @@ module.exports = (function() {
}) })
.error( function (error) { .error( function (error) {
emitter.emit('error', error) emitter.emit('error', error)
}); })
} else { } else {
emitter.emit('success', instance) emitter.emit('success', instance)
} }
...@@ -368,6 +373,45 @@ module.exports = (function() { ...@@ -368,6 +373,45 @@ module.exports = (function() {
}.bind(this)) }.bind(this))
} }
var validateIncludedElement = function(include) {
if (include instanceof DAOFactory) {
include = { daoFactory: include, as: include.tableName }
}
if (typeof include === 'object') {
if (include.hasOwnProperty('model')) {
include.daoFactory = include.model
delete include.model
}
if (include.hasOwnProperty('daoFactory') && (include.hasOwnProperty('as'))) {
var usesAlias = (include.as !== include.daoFactory.tableName)
, association = (usesAlias ? this.getAssociationByAlias(include.as) : this.getAssociation(include.daoFactory))
// check if the current daoFactory is actually associated with the passed daoFactory
if (!!association && (!association.options.as || (association.options.as === include.as))) {
include.association = association
return include
} else {
var msg = include.daoFactory.name
if (usesAlias) {
msg += " (" + include.as + ")"
}
msg += " is not associated to " + this.name + "!"
throw new Error(msg)
}
} else {
throw new Error('Include malformed. Expected attributes: daoFactory, as!')
}
} else {
throw new Error('Include unexpected. Element has to be either an instance of DAOFactory or an object.')
}
}
Utils._.extend(DAOFactory.prototype, require("./associations/mixin")) Utils._.extend(DAOFactory.prototype, require("./associations/mixin"))
return DAOFactory return DAOFactory
......
...@@ -141,29 +141,21 @@ module.exports = (function() { ...@@ -141,29 +141,21 @@ module.exports = (function() {
* @return {String} The found tableName / alias. * @return {String} The found tableName / alias.
*/ */
var findTableNameInAttribute = function(attribute) { var findTableNameInAttribute = function(attribute) {
var tableName = null if (!this.options.include) {
return null
this.sequelize.daoFactoryManager.daos.forEach(function(daoFactory) {
if (!!tableName) {
return
} else if (attribute.indexOf(daoFactory.tableName + ".") === 0) {
tableName = daoFactory.tableName
} else if (attribute.indexOf(Utils.singularize(daoFactory.tableName) + ".") === 0) {
tableName = Utils.singularize(daoFactory.tableName)
} else {
for (var associationName in daoFactory.associations) {
if (daoFactory.associations.hasOwnProperty(associationName)) {
var association = daoFactory.associations[associationName]
if (attribute.indexOf(association.options.as + ".") === 0) {
tableName = association.options.as
}
}
}
} }
var tableNames = this.options.include.map(function(include) {
return include.as
}).filter(function(include) {
return attribute.indexOf(include + '.') === 0
}) })
return tableName if (tableNames.length === 1) {
return tableNames[0]
} else {
return null
}
} }
var queryResultHasJoin = function(results) { var queryResultHasJoin = function(results) {
......
...@@ -131,49 +131,24 @@ module.exports = (function() { ...@@ -131,49 +131,24 @@ module.exports = (function() {
if (options.include) { if (options.include) {
var optAttributes = [options.table + '.*'] var optAttributes = [options.table + '.*']
for (var daoName in options.include) { options.include.forEach(function(include) {
if (options.include.hasOwnProperty(daoName)) { var attributes = Object.keys(include.daoFactory.attributes).map(function(attr) {
var dao = options.include[daoName] var template = Utils._.template("`<%= as %>`.`<%= attr %>` AS `<%= as %>.<%= attr %>`")
, daoFactory = dao.daoFactoryManager.getDAO(tableName, { return template({ as: include.as, attr: attr })
attribute: 'tableName'
}) })
, _tableName = Utils.addTicks(dao.tableName)
, association = dao.getAssociation(daoFactory)
if (association.connectorDAO) {
var foreignIdentifier = Object.keys(association.connectorDAO.rawAttributes).filter(function(attrName) {
return (!!attrName.match(/.+Id$/) || !!attrName.match(/.+_id$/)) && (attrName !== association.identifier)
})[0]
query += ' LEFT OUTER JOIN ' + Utils.addTicks(association.connectorDAO.tableName) + ' ON '
query += Utils.addTicks(association.connectorDAO.tableName) + '.'
query += Utils.addTicks(foreignIdentifier) + '='
query += Utils.addTicks(table) + '.' + Utils.addTicks('id')
query += ' LEFT OUTER JOIN ' + Utils.addTicks(dao.tableName) + ' ON '
query += Utils.addTicks(dao.tableName) + '.'
query += Utils.addTicks('id') + '='
query += Utils.addTicks(association.connectorDAO.tableName) + '.' + Utils.addTicks(association.identifier)
} else {
query += ' LEFT OUTER JOIN ' + Utils.addTicks(dao.tableName) + ' ON '
query += Utils.addTicks(association.associationType === 'BelongsTo' ? dao.tableName : tableName) + '.'
query += Utils.addTicks(association.identifier) + '='
query += Utils.addTicks(association.associationType === 'BelongsTo' ? tableName : dao.tableName) + '.' + Utils.addTicks('id')
}
var aliasAssoc = daoFactory.getAssociationByAlias(daoName) optAttributes = optAttributes.concat(attributes)
, aliasName = !!aliasAssoc ? Utils.addTicks(daoName) : _tableName
optAttributes = optAttributes.concat( var joinQuery = " LEFT OUTER JOIN `<%= table %>` AS `<%= as %>` ON `<%= tableLeft %>`.`<%= attrLeft %>` = `<%= tableRight %>`.`<%= attrRight %>`"
Object.keys(dao.attributes).map(function(attr) { query += Utils._.template(joinQuery)({
return '' + table: include.daoFactory.tableName,
[_tableName, Utils.addTicks(attr)].join('.') + as: include.as,
' AS ' + tableLeft: ((include.association.associationType === 'BelongsTo') ? include.as : tableName),
Utils.addTicks([aliasName, attr].join('.')) attrLeft: 'id',
tableRight: ((include.association.associationType === 'BelongsTo') ? tableName : include.as),
attrRight: include.association.identifier
})
}) })
)
}
}
options.attributes = optAttributes.join(', ') options.attributes = optAttributes.join(', ')
} }
......
...@@ -31,7 +31,9 @@ module.exports = (function() { ...@@ -31,7 +31,9 @@ module.exports = (function() {
} }
var query = new Query(this.client, this.sequelize, callee, options || {}) var query = new Query(this.client, this.sequelize, callee, options || {})
self.pendingQueries += 1 self.pendingQueries += 1
return query.run(sql) return query.run(sql)
.success(function() { self.endQuery.call(self) }) .success(function() { self.endQuery.call(self) })
.error(function() { self.endQuery.call(self) }) .error(function() { self.endQuery.call(self) })
......
...@@ -233,49 +233,24 @@ module.exports = (function() { ...@@ -233,49 +233,24 @@ module.exports = (function() {
if (options.include) { if (options.include) {
var optAttributes = [options.table + '.*'] var optAttributes = [options.table + '.*']
for (var daoName in options.include) { options.include.forEach(function(include) {
if (options.include.hasOwnProperty(daoName)) { var attributes = Object.keys(include.daoFactory.attributes).map(function(attr) {
var dao = options.include[daoName] var template = Utils._.template('"<%= as %>"."<%= attr %>" AS "<%= as %>.<%= attr %>"')
, daoFactory = dao.daoFactoryManager.getDAO(tableName, { return template({ as: include.as, attr: attr })
attribute: 'tableName'
}) })
, _tableName = addQuotes(dao.tableName)
, association = dao.getAssociation(daoFactory)
if (association.connectorDAO) {
var foreignIdentifier = Object.keys(association.connectorDAO.rawAttributes).filter(function(attrName) {
return (!!attrName.match(/.+Id$/) || !!attrName.match(/.+_id$/)) && (attrName !== association.identifier)
})[0]
query += ' LEFT OUTER JOIN ' + addQuotes(association.connectorDAO.tableName) + ' ON '
query += addQuotes(association.connectorDAO.tableName) + '.'
query += addQuotes(foreignIdentifier) + '='
query += addQuotes(table) + '.' + addQuotes('id')
query += ' LEFT OUTER JOIN ' + addQuotes(dao.tableName) + ' ON '
query += addQuotes(dao.tableName) + '.'
query += addQuotes('id') + '='
query += addQuotes(association.connectorDAO.tableName) + '.' + addQuotes(association.identifier)
} else {
query += ' LEFT OUTER JOIN ' + addQuotes(dao.tableName) + ' ON '
query += addQuotes(association.associationType === 'BelongsTo' ? dao.tableName : tableName) + '.'
query += addQuotes(association.identifier) + '='
query += addQuotes(association.associationType === 'BelongsTo' ? tableName : dao.tableName) + '.' + addQuotes('id')
}
var aliasAssoc = daoFactory.getAssociationByAlias(daoName) optAttributes = optAttributes.concat(attributes)
, aliasName = !!aliasAssoc ? addQuotes(daoName) : _tableName
optAttributes = optAttributes.concat( var joinQuery = ' LEFT OUTER JOIN "<%= table %>" AS "<%= as %>" ON "<%= tableLeft %>"."<%= attrLeft %>" = "<%= tableRight %>"."<%= attrRight %>"'
Object.keys(dao.attributes).map(function(attr) { query += Utils._.template(joinQuery)({
return '' + table: include.daoFactory.tableName,
[_tableName, addQuotes(attr)].join('.') + as: include.as,
' AS "' + tableLeft: ((include.association.associationType === 'BelongsTo') ? include.as : tableName),
removeQuotes([aliasName, attr].join('.')) + '"' attrLeft: 'id',
tableRight: ((include.association.associationType === 'BelongsTo') ? tableName : include.as),
attrRight: include.association.identifier
})
}) })
)
}
}
options.attributes = optAttributes.join(', ') options.attributes = optAttributes.join(', ')
} }
......
...@@ -198,14 +198,17 @@ module.exports = (function() { ...@@ -198,14 +198,17 @@ module.exports = (function() {
} }
QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) { QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) {
options = options || {}
var sql = this.QueryGenerator.selectQuery(tableName, options) var sql = this.QueryGenerator.selectQuery(tableName, options)
queryOptions = Utils._.extend({}, queryOptions, { include: options.include })
return queryAndEmit.call(this, [sql, factory, queryOptions], 'select') return queryAndEmit.call(this, [sql, factory, queryOptions], 'select')
} }
QueryInterface.prototype.rawSelect = function(tableName, options, attributeSelector) { QueryInterface.prototype.rawSelect = function(tableName, options, attributeSelector) {
var self = this var self = this
if (attributeSelector == undefined) { if (attributeSelector === undefined) {
throw new Error('Please pass an attribute selector!') throw new Error('Please pass an attribute selector!')
} }
......
...@@ -10,20 +10,28 @@ if (typeof process != 'undefined' && parseFloat(process.version.replace('v', '') ...@@ -10,20 +10,28 @@ if (typeof process != 'undefined' && parseFloat(process.version.replace('v', '')
module.exports = (function() { module.exports = (function() {
/** /**
Main constructor of the project. Main class of the project.
Params: @param {String} database The name of the database.
@param {String} username The username which is used to authenticate against the database.
@param {String} [password] The password which is used to authenticate against the database.
@param {Object} [options] An object with options.
- `database` @example
- `username` // without password and options
- `password`, optional, default: null var sequelize = new Sequelize('database', 'username')
- `options`, optional, default: {}
Examples: // without options
var sequelize = new Sequelize('database', 'username', 'password')
mymodule.write('foo') // without password / with blank password
mymodule.write('foo', { stream: process.stderr }) var sequelize = new Sequelize('database', 'username', null, {})
// with password and options
var sequelize = new Sequelize('my_database', 'john', 'doe', {})
@class Sequelize
@constructor
*/ */
var Sequelize = function(database, username, password, options) { var Sequelize = function(database, username, password, options) {
this.options = Utils._.extend({ this.options = Utils._.extend({
......
...@@ -36,8 +36,8 @@ ...@@ -36,8 +36,8 @@
"mysql": "~2.0.0-alpha7", "mysql": "~2.0.0-alpha7",
"pg": "~0.10.2", "pg": "~0.10.2",
"buster": "~0.6.0", "buster": "~0.6.0",
"dox-foundation": "~0.3.0", "watchr": "~2.2.0",
"watchr": "~2.2.0" "yuidocjs": "~0.3.36"
}, },
"keywords": [ "keywords": [
"mysql", "mysql",
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
"test-buster-postgres": "DIALECT=postgres ./node_modules/.bin/buster-test", "test-buster-postgres": "DIALECT=postgres ./node_modules/.bin/buster-test",
"test-buster-postgres-native": "DIALECT=postgres-native ./node_modules/.bin/buster-test", "test-buster-postgres-native": "DIALECT=postgres-native ./node_modules/.bin/buster-test",
"test-buster-sqlite": "DIALECT=sqlite ./node_modules/.bin/buster-test", "test-buster-sqlite": "DIALECT=sqlite ./node_modules/.bin/buster-test",
"generate-docs": "node_modules/.bin/dox-foundation --source ./lib --target ./docs --title Sequelize" "docs": "node_modules/.bin/yuidoc . -o docs"
}, },
"bin": { "bin": {
"sequelize": "bin/sequelize" "sequelize": "bin/sequelize"
......
...@@ -2,6 +2,7 @@ const Sequelize = require(__dirname + "/../index") ...@@ -2,6 +2,7 @@ const Sequelize = require(__dirname + "/../index")
, DataTypes = require(__dirname + "/../lib/data-types") , DataTypes = require(__dirname + "/../lib/data-types")
, config = require(__dirname + "/config/config") , config = require(__dirname + "/config/config")
, fs = require('fs') , fs = require('fs')
, buster = require("buster")
var BusterHelpers = module.exports = { var BusterHelpers = module.exports = {
Sequelize: Sequelize, Sequelize: Sequelize,
...@@ -95,5 +96,14 @@ var BusterHelpers = module.exports = { ...@@ -95,5 +96,14 @@ var BusterHelpers = module.exports = {
} else { } else {
throw new Error('Undefined expectation for "' + dialect + '"!') throw new Error('Undefined expectation for "' + dialect + '"!')
} }
},
assertException: function(block, msg) {
try {
block()
throw new Error('Passed function did not throw an error')
} catch(e) {
buster.assert.equals(e.message, msg)
}
} }
} }
...@@ -52,18 +52,12 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -52,18 +52,12 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it("throws an error if 2 autoIncrements are passed", function() { it("throws an error if 2 autoIncrements are passed", function() {
try { Helpers.assertException(function() {
var User = this.sequelize.define('UserWithTwoAutoIncrements', { this.sequelize.define('UserWithTwoAutoIncrements', {
userid: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }, userid: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
userscore: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true } userscore: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }
}) })
// the parse shouldn't execute the following line }.bind(this), 'Invalid DAO definition. Only one autoincrement field allowed.')
// this tests needs to be refactored...
// we need to use expect.toThrow when a later version than 0.6 was released
expect(1).toEqual(2)
} catch(e) {
expect(e.message).toEqual('Invalid DAO definition. Only one autoincrement field allowed.')
}
}) })
}) })
...@@ -205,18 +199,12 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -205,18 +199,12 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
}) })
it('raises an error if you mess up the datatype', function(done) { it('raises an error if you mess up the datatype', function() {
Helpers.assertException(function() {
try { this.sequelize.define('UserBadDataType', {
var User = this.sequelize.define('UserBadDataType', {
activity_date: Sequelize.DATe activity_date: Sequelize.DATe
}); })
done() }.bind(this), 'Unrecognized data type for field activity_date')
}
catch( e ) {
expect(e.message).toEqual('Unrecognized data type for field activity_date')
done()
}
}) })
it('sets a 64 bit int in bigint', function(done) { it('sets a 64 bit int in bigint', function(done) {
...@@ -466,769 +454,509 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -466,769 +454,509 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}.bind(this)) }.bind(this))
}) })
describe('association fetching', function() { describe('eager loading', function() {
before(function() { before(function() {
this.Task = this.sequelize.define('Task', { this.Task = this.sequelize.define('Task', { title: Sequelize.STRING })
title: Sequelize.STRING this.Worker = this.sequelize.define('Worker', { name: Sequelize.STRING })
})
this.User = this.sequelize.define('UserWithName', { this.init = function(callback) {
name: Sequelize.STRING this.sequelize.sync({ force: true }).complete(function() {
}) this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
callback()
}.bind(this))
}.bind(this))
}.bind(this))
}.bind(this)
}) })
describe('1:1 associations', function() { describe('belongsTo', function() {
it('fetches associated objects (1st direction)', function(done) { before(function(done) {
this.User.hasOne(this.Task) this.Task.belongsTo(this.Worker)
this.Task.belongsTo(this.User) this.init(function() {
this.task.setWorker(this.worker).success(done)
}.bind(this))
})
this.sequelize.sync({ force: true }).success(function() { it('throws an error about unexpected input if include contains a non-object', function() {
this.User.create({ name: 'barfooz' }).success(function(user) { Helpers.assertException(function() {
this.Task.create({ title: 'task' }).success(function(task) { this.Worker.find({ include: [ 1 ] })
user.setTask(task).success(function() { }.bind(this), 'Include unexpected. Element has to be either an instance of DAOFactory or an object.')
this.User.find({
where: { 'UserWithNames.id': 1 },
include: [ 'Task' ]
}).success(function(user) {
expect(user.task).toBeDefined()
expect(user.task.id).toEqual(task.id)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create it('throws an error about missing attributes if include contains an object with daoFactory', function() {
}.bind(this)) //- User.create Helpers.assertException(function() {
}.bind(this)) //- sequelize.sync this.Worker.find({ include: [ { daoFactory: this.Worker } ] })
}.bind(this), 'Include malformed. Expected attributes: daoFactory, as!')
}) })
it('fetches no associated object if none is set (1st direction)', function(done) { it('throws an error if included DaoFactory is not associated', function() {
this.User.hasOne(this.Task) Helpers.assertException(function() {
this.Task.belongsTo(this.User) this.Worker.find({ include: [ this.Task ] })
}.bind(this), 'Task is not associated to Worker!')
})
this.sequelize.sync({ force: true }).success(function() { it('returns the associated worker via task.worker', function(done) {
this.User.create({ name: 'barfooz' }).success(function(user) { this.Task.find({
this.Task.create({ title: 'task' }).success(function(task) { where: { title: 'homework' },
this.User.find({ include: [ this.Worker ]
where: { 'UserWithNames.id': 1 }, }).complete(function(err, task) {
include: [ 'Task' ] expect(err).toBeNull()
}).success(function(user) { expect(task).toBeDefined()
expect(user.task).toEqual(null) expect(task.worker).toBeDefined()
expect(task.worker.name).toEqual('worker')
done() done()
}) }.bind(this))
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated objects via "as" param (1st direction)', function(done) { it('returns the private and public ip', function(done) {
this.User.hasOne(this.Task, { as: 'Homework' }) var Domain = this.sequelize.define('Domain', { ip: Sequelize.STRING })
this.Task.belongsTo(this.User) var Environment = this.sequelize.define('Environment', { name: Sequelize.STRING })
this.sequelize.sync({ force: true }).success(function() { Environment
this.User.create({ name: 'barfooz' }).success(function(user) { .belongsTo(Domain, { as: 'PrivateDomain', foreignKey: 'privateDomainId' })
this.Task.create({ title: 'task' }).success(function(task) { .belongsTo(Domain, { as: 'PublicDomain', foreignKey: 'publicDomainId' })
user.setHomework(task).success(function() {
this.User.find({ this.sequelize.sync({ force: true }).complete(function() {
where: { 'UserWithNames.id': 1 }, Domain.create({ ip: '192.168.0.1' }).success(function(privateIp) {
include: [ 'Homework' ] Domain.create({ ip: '91.65.189.19' }).success(function(publicIp) {
}).success(function(user) { Environment.create({ name: 'environment' }).success(function(env) {
expect(user.homework).toBeDefined() env.setPrivateDomain(privateIp).success(function() {
expect(user.homework.id).toEqual(task.id) env.setPublicDomain(publicIp).success(function() {
Environment.find({
where: { name: 'environment' },
include: [
{ daoFactory: Domain, as: 'PrivateDomain' },
{ daoFactory: Domain, as: 'PublicDomain' }
]
}).complete(function(err, environment) {
expect(err).toBeNull()
expect(environment).toBeDefined()
expect(environment.privateDomain).toBeDefined()
expect(environment.privateDomain.ip).toEqual('192.168.0.1')
expect(environment.publicDomain).toBeDefined()
expect(environment.publicDomain.ip).toEqual('91.65.189.19')
done() done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated object (2nd direction)', function(done) {
this.User.hasOne(this.Task)
this.Task.belongsTo(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.User.create({ name: 'another user' }).success(function(another_user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
this.Task.find({
where: { 'Tasks.id': 1 },
include: [ 'UserWithName' ]
}).success(function(task) {
expect(task.userWithName).toBeDefined()
expect(task.userWithName.id).toEqual(user.id)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches no associated object if none is set (2nd direction)', function(done) {
this.User.hasOne(this.Task)
this.Task.belongsTo(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.User.create({ name: 'another user' }).success(function(another_user) {
this.Task.create({ title: 'task' }).success(function(task) {
this.Task.find({
where: { 'Tasks.id': 1 },
include: [ 'UserWithName' ]
}).success(function(task) {
expect(task.userWithName).toEqual(null)
done()
}) })
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated object via "as" param (2nd direction)', function(done) {
this.User.hasOne(this.Task)
this.Task.belongsTo(this.User, { as: 'Owner' })
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.User.create({ name: 'another user' }).success(function(another_user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
this.Task.find({
where: { 'Tasks.id': 1 },
include: [ 'Owner' ]
}).success(function(task) {
expect(task.owner).toBeDefined()
expect(task.owner.id).toEqual(user.id)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
}) })
it('fetches associated objects for 1:N associations (1st direction)', function(done) { describe('hasOne', function() {
this.User.hasMany(this.Task) before(function(done) {
this.Task.belongsTo(this.User) this.Worker.hasOne(this.Task)
this.sequelize.sync({ force: true }).complete(function() {
this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.sequelize.sync({ force: true }).success(function() { this.worker.setTask(this.task).success(done)
this.User.create({ name: 'barfooz' }).success(function(user) { }.bind(this))
this.Task.create({ title: 'task1' }).success(function(task1) { }.bind(this))
this.Task.create({ title: 'task2' }).success(function(task2) { }.bind(this))
user.setTasks([task1, task2]).success(function() {
this.User.find({
where: { 'UserWithNames.id': 1 },
include: [ 'Task' ]
}).success(function(user) {
expect(user.tasks).toBeDefined()
expect(
user.tasks.map(function(t) { return t.id })
).toEqual(
[ task1.id, task2.id ]
)
done()
})
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated objects via "as" param for 1:N associations (1st direction)', function(done) { it('throws an error if included DaoFactory is not associated', function() {
this.User.hasMany(this.Task, { as: 'Homeworks' }) Helpers.assertException(function() {
this.Task.belongsTo(this.User) this.Task.find({ include: [ this.Worker ] })
}.bind(this), 'Worker is not associated to Task!')
})
this.sequelize.sync({ force: true }).success(function() { it('returns the associated task via worker.task', function(done) {
this.User.create({ name: 'barfooz' }).success(function(user) { this.Worker.find({
this.Task.create({ title: 'task1' }).success(function(task1) { where: { name: 'worker' },
this.Task.create({ title: 'task2' }).success(function(task2) { include: [ this.Task ]
user.setHomeworks([task1, task2]).success(function() { }).complete(function(err, worker) {
this.User.find({ expect(err).toBeNull()
where: { 'UserWithNames.id': 1 }, expect(worker).toBeDefined()
include: [ 'Homeworks' ] expect(worker.task).toBeDefined()
}).success(function(user) { expect(worker.task.title).toEqual('homework')
expect(user.homeworks).toBeDefined()
expect(
user.homeworks.map(function(t) { return t.id })
).toEqual(
[ task1.id, task2.id ]
)
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches no associated objects for 1:N associations if none are set (1st direction)', function(done) { describe('hasOne with alias', function() {
this.User.hasMany(this.Task) before(function(done) {
this.Task.belongsTo(this.User) this.Worker.hasOne(this.Task, { as: 'ToDo' })
this.sequelize.sync({ force: true }).success(function() { this.sequelize.sync({ force: true }).complete(function() {
this.User.create({ name: 'barfooz' }).success(function(user) { this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'task1' }).success(function(task1) { this.Task.create({ title: 'homework' }).success(function(task) {
this.User.find({ this.worker = worker
where: { 'UserWithNames.id': 1 }, this.task = task
include: [ 'Task' ]
}).success(function(user) { this.worker.setToDo(this.task).success(done)
expect(user.tasks.length).toEqual(0) }.bind(this))
done() }.bind(this))
}.bind(this))
}) })
}.bind(this)) //- Task.create
}.bind(this)) //- User.create it('throws an error if included DaoFactory is not referenced by alias', function() {
}.bind(this)) //- sequelize.sync Helpers.assertException(function() {
this.Worker.find({ include: [ this.Task ] })
}.bind(this), 'Task is not associated to Worker!')
}) })
it('fetches associated objects for 1:N associations (2nd direction)', function(done) { it('throws an error if alias is not associated', function() {
this.User.hasMany(this.Task) Helpers.assertException(function() {
this.Task.belongsTo(this.User) this.Worker.find({ include: [ { daoFactory: this.Task, as: 'Work' } ] })
}.bind(this), 'Task (Work) is not associated to Worker!')
})
this.sequelize.sync({ force: true }).success(function() { it('returns the associated task via worker.task', function(done) {
this.User.create({ name: 'barfooz' }).success(function(user) { this.Worker.find({
this.Task.create({ title: 'task1' }).success(function(task1) { where: { name: 'worker' },
this.Task.create({ title: 'task2' }).success(function(task2) { include: [ { daoFactory: this.Task, as: 'ToDo' } ]
user.setTasks([task1, task2]).success(function() { }).complete(function(err, worker) {
this.Task.find({ expect(err).toBeNull()
where: { 'Tasks.id': 1 }, expect(worker).toBeDefined()
include: [ 'UserWithName' ] expect(worker.toDo).toBeDefined()
}).success(function(task) { expect(worker.toDo.title).toEqual('homework')
expect(task.userWithName).toBeDefined()
expect(task.userWithName.name).toEqual(user.name)
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
})
it('fetches associated objects via "as" param for 1:N associations (2nd direction)', function(done) {
this.User.hasMany(this.Task)
this.Task.belongsTo(this.User, { as: 'Owner'})
this.sequelize.sync({ force: true }).success(function() { it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
this.User.create({ name: 'barfooz' }).success(function(user) { this.Worker.find({
this.Task.create({ title: 'task1' }).success(function(task1) { where: { name: 'worker' },
this.Task.create({ title: 'task2' }).success(function(task2) { include: [ { model: this.Task, as: 'ToDo' } ]
user.setTasks([task1, task2]).success(function() { }).complete(function(err, worker) {
this.Task.find({ expect(worker.toDo.title).toEqual('homework')
where: { 'Tasks.id': 1 },
include: [ 'Owner' ]
}).success(function(task) {
expect(task.owner).toBeDefined()
expect(task.owner.name).toEqual(user.name)
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated objects for N:M associations (1st direction)', function(done) { describe('hasMany', function() {
this.User.hasMany(this.Task) before(function(done) {
this.Task.hasMany(this.User) this.Worker.hasMany(this.Task)
this.sequelize.sync({ force: true }).success(function() { this.sequelize.sync({ force: true }).complete(function() {
this.User.create({ name: 'barfooz' }).success(function(user1) { this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.Task.create({ title: 'task1' }).success(function(task1) { this.worker.setTasks([ this.task ]).success(done)
this.Task.create({ title: 'task2' }).success(function(task2) { }.bind(this))
user1.setTasks([task1, task2]).success(function() { }.bind(this))
this.User.find({ }.bind(this))
where: { 'UserWithNames.id': user1.id },
include: [ 'Task' ]
}).success(function(user) {
expect(user.tasks).toBeDefined()
expect(
user.tasks.map(function(t) { return t.id })
).toEqual(
[ task1.id, task2.id ]
)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create it('throws an error if included DaoFactory is not associated', function() {
}.bind(this)) //- sequelize.sync Helpers.assertException(function() {
this.Task.find({ include: [ this.Worker ] })
}.bind(this), 'Worker is not associated to Task!')
}) })
it('fetches no associated objects for N:M associations if none are set (1st direction)', function(done) { it('returns the associated tasks via worker.tasks', function(done) {
this.User.hasMany(this.Task) this.Worker.find({
this.Task.hasMany(this.User) where: { name: 'worker' },
include: [ this.Task ]
this.sequelize.sync({ force: true }).success(function() { }).complete(function(err, worker) {
this.User.create({ name: 'barfooz' }).success(function(user1) { expect(err).toBeNull()
expect(worker).toBeDefined()
this.Task.create({ title: 'task1' }).success(function(task1) { expect(worker.tasks).toBeDefined()
this.Task.create({ title: 'task2' }).success(function(task2) { expect(worker.tasks[0].title).toEqual('homework')
this.User.find({
where: { 'UserWithNames.id': user1.id },
include: [ 'Task' ]
}).success(function(user) {
expect(user.tasks.length).toEqual(0)
done() done()
}.bind(this))
}) })
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated objects via "as" param for N:M associations (1st direction)', function(done) { describe('hasMany with alias', function() {
this.User.hasMany(this.Task, { as: 'Homeworks' }) before(function(done) {
this.Task.hasMany(this.User, { as: 'Owners' }) this.Worker.hasMany(this.Task, { as: 'ToDos' })
this.sequelize.sync({ force: true }).success(function() { this.sequelize.sync({ force: true }).complete(function() {
this.User.create({ name: 'barfooz' }).success(function(user1) { this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.Task.create({ title: 'task1' }).success(function(task1) { this.worker.setToDos([ this.task ]).success(done)
this.Task.create({ title: 'task2' }).success(function(task2) { }.bind(this))
user1.setHomeworks([task1, task2]).success(function() { }.bind(this))
this.User.find({ }.bind(this))
where: { 'UserWithNames.id': user1.id },
include: [ 'Homeworks' ]
}).success(function(user) {
expect(user.homeworks).toBeDefined()
expect(
user.homeworks.map(function(t) { return t.id })
).toEqual(
[ task1.id, task2.id ]
)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create it('throws an error if included DaoFactory is not referenced by alias', function() {
}.bind(this)) //- sequelize.sync Helpers.assertException(function() {
this.Worker.find({ include: [ this.Task ] })
}.bind(this), 'Task is not associated to Worker!')
}) })
it('fetches associated objects for N:M associations (2nd direction)', function(done) { it('throws an error if alias is not associated', function() {
this.User.hasMany(this.Task) Helpers.assertException(function() {
this.Task.hasMany(this.User) this.Worker.find({ include: [ { daoFactory: this.Task, as: 'Work' } ] })
}.bind(this), 'Task (Work) is not associated to Worker!')
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user1) {
this.Task.create({ title: 'task1' }).success(function(task1) {
this.Task.create({ title: 'task2' }).success(function(task2) {
user1.setTasks([task1, task2]).success(function() {
this.Task.find({
where: { 'Tasks.id': task1.id },
include: [ 'UserWithName' ]
}).success(function(task) {
expect(task.userWithNames).toBeDefined()
expect(
task.userWithNames.map(function(u) { return u.id })
).toEqual(
[ user1.id ]
)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create it('returns the associated task via worker.task', function(done) {
}.bind(this)) //- sequelize.sync this.Worker.find({
where: { name: 'worker' },
include: [ { daoFactory: this.Task, as: 'ToDos' } ]
}).complete(function(err, worker) {
expect(err).toBeNull()
expect(worker).toBeDefined()
expect(worker.toDos).toBeDefined()
expect(worker.toDos[0].title).toEqual('homework')
done()
}.bind(this))
}) })
it('fetches associated objects via "as" param for N:M associations (2nd direction)', function(done) { it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
this.User.hasMany(this.Task, { as: 'Homeworks' }) this.Worker.find({
this.Task.hasMany(this.User, { as: 'Owners' }) where: { name: 'worker' },
include: [ { model: this.Task, as: 'ToDos' } ]
this.sequelize.sync({ force: true }).success(function() { }).complete(function(err, worker) {
this.User.create({ name: 'barfooz' }).success(function(user1) { expect(worker.toDos[0].title).toEqual('homework')
this.Task.create({ title: 'task1' }).success(function(task1) {
this.Task.create({ title: 'task2' }).success(function(task2) {
user1.setHomeworks([task1, task2]).success(function() {
this.Task.find({
where: { 'Tasks.id': task1.id },
include: [ 'Owners' ]
}).success(function(task) {
expect(task.owners).toBeDefined()
expect(
task.owners.map(function(u) { return u.id })
).toEqual(
[ user1.id ]
)
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
}) })
}) //- describe: find }) //- describe: find
describe('findAll', function findAll() { describe('findAll', function findAll() {
describe('include', function() { describe('eager loading', function() {
before(function() { before(function() {
this.Task = this.sequelize.define('Task', { this.Task = this.sequelize.define('Task', { title: Sequelize.STRING })
title: Sequelize.STRING this.Worker = this.sequelize.define('Worker', { name: Sequelize.STRING })
}) })
this.User = this.sequelize.define('UserWithName', { describe('belongsTo', function() {
name: Sequelize.STRING before(function(done) {
}) this.Task.belongsTo(this.Worker)
})
it('fetches data only for the relevant where clause', function(done) {
this.User.hasOne(this.Task)
this.Task.belongsTo(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user1) {
this.User.create({ name: 'barfooz' }).success(function(user2) {
this.Task.create({ title: 'task' }).success(function(task) {
var where = [Sequelize.Utils.addTicks(this.User.tableName) + ".`id`=?", user1.id]
if (dialect === 'postgres') { this.sequelize.sync({ force: true }).complete(function() {
where = ['"' + this.User.tableName + '"."id"=?', user1.id] this.Worker.create({ name: 'worker' }).success(function(worker) {
} this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.User.findAll({ this.task.setWorker(this.worker).success(done)
where: where,
include: [ 'Task' ]
}).success(function(users){
expect(users.length).toEqual(1)
// console.log(users[0])
done()
}.bind(this))
}.bind(this))
}.bind(this)) }.bind(this))
}.bind(this)) }.bind(this))
}.bind(this)) }.bind(this))
}) })
it('fetches associated objects for 1:1 associations (1st direction)', function(done) { it('throws an error about unexpected input if include contains a non-object', function() {
this.User.hasOne(this.Task) Helpers.assertException(function() {
this.Task.belongsTo(this.User) this.Worker.findAll({ include: [ 1 ] })
}.bind(this), 'Include unexpected. Element has to be either an instance of DAOFactory or an object.')
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
this.User.findAll({
where: { 'UserWithNames.id': 1 },
include: [ 'Task' ]
}).success(function(users) {
expect(users[0].task).toBeDefined()
expect(users[0].task.id).toEqual(task.id)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create it('throws an error about missing attributes if include contains an object with daoFactory', function() {
}.bind(this)) //- User.create Helpers.assertException(function() {
}.bind(this)) //- sequelize.sync this.Worker.findAll({ include: [ { daoFactory: this.Worker } ] })
}) }.bind(this), 'Include malformed. Expected attributes: daoFactory, as!')
it('fetches associated objects via "as" param for 1:1 associations (1st direction)', function(done) {
this.User.hasOne(this.Task, { as: 'Homework' })
this.Task.belongsTo(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setHomework(task).success(function() {
this.User.findAll({
where: { 'UserWithNames.id': 1 },
include: [ 'Homework' ]
}).success(function(users) {
expect(users[0].homework).toBeDefined()
expect(users[0].homework.id).toEqual(task.id)
done()
})
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated objects for 1:1 associations (2nd direction)', function(done) { it('throws an error if included DaoFactory is not associated', function() {
this.User.hasOne(this.Task) Helpers.assertException(function() {
this.Task.belongsTo(this.User) this.Worker.findAll({ include: [ this.Task ] })
}.bind(this), 'Task is not associated to Worker!')
})
this.sequelize.sync({ force: true }).success(function() { it('returns the associated worker via task.worker', function(done) {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() {
this.Task.findAll({ this.Task.findAll({
where: { 'Tasks.id': 1 }, where: { title: 'homework' },
include: [ 'UserWithName' ] include: [ this.Worker ]
}).success(function(tasks) { }).complete(function(err, tasks) {
expect(tasks[0].userWithName).toBeDefined() expect(err).toBeNull()
expect(tasks[0].userWithName.id).toEqual(user.id) expect(tasks).toBeDefined()
expect(tasks[0].worker).toBeDefined()
expect(tasks[0].worker.name).toEqual('worker')
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated objects for 1:1 associations (2nd direction)', function(done) { describe('hasOne', function() {
this.User.hasOne(this.Task) before(function(done) {
this.Task.belongsTo(this.User, { as: 'Owner' }) this.Worker.hasOne(this.Task)
this.sequelize.sync({ force: true }).success(function() { this.sequelize.sync({ force: true }).complete(function() {
this.User.create({ name: 'barfooz' }).success(function(user) { this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'task' }).success(function(task) { this.Task.create({ title: 'homework' }).success(function(task) {
user.setTask(task).success(function() { this.worker = worker
this.Task.findAll({ this.task = task
where: { 'Tasks.id': 1 },
include: [ 'Owner' ] this.worker.setTask(this.task).success(done)
}).success(function(tasks) { }.bind(this))
expect(tasks[0].owner).toBeDefined() }.bind(this))
expect(tasks[0].owner.id).toEqual(user.id) }.bind(this))
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create it('throws an error if included DaoFactory is not associated', function() {
}.bind(this)) //- User.create Helpers.assertException(function() {
}.bind(this)) //- sequelize.sync this.Task.findAll({ include: [ this.Worker ] })
}) }.bind(this), 'Worker is not associated to Task!')
it('fetches associated objects for 1:N associations (1st direction)', function(done) {
this.User.hasMany(this.Task)
this.Task.belongsTo(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.Task.create({ title: 'task1' }).success(function(task1) {
this.Task.create({ title: 'task2' }).success(function(task2) {
user.setTasks([task1, task2]).success(function() {
this.User.findAll({
where: { 'UserWithNames.id': 1 },
include: [ 'Task' ]
}).success(function(users) {
expect(users[0].tasks).toBeDefined()
expect(
users[0].tasks.map(function(t) { return t.id })
).toEqual(
[ task1.id, task2.id ]
)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create it('returns the associated task via worker.task', function(done) {
}.bind(this)) //- Task.create this.Worker.findAll({
}.bind(this)) //- User.create where: { name: 'worker' },
}.bind(this)) //- sequelize.sync include: [ this.Task ]
}) }).complete(function(err, workers) {
expect(err).toBeNull()
it('fetches associated objects for 1:N associations (1st direction)', function(done) { expect(workers).toBeDefined()
this.User.hasMany(this.Task, { as: 'Homeworks' }) expect(workers[0].task).toBeDefined()
this.Task.belongsTo(this.User) expect(workers[0].task.title).toEqual('homework')
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user) {
this.Task.create({ title: 'task1' }).success(function(task1) {
this.Task.create({ title: 'task2' }).success(function(task2) {
user.setHomeworks([task1, task2]).success(function() {
this.User.findAll({
where: { 'UserWithNames.id': 1 },
include: [ 'Homeworks' ]
}).success(function(users) {
expect(users[0].homeworks).toBeDefined()
expect(
users[0].homeworks.map(function(t) { return t.id })
).toEqual(
[ task1.id, task2.id ]
)
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
}) })
it('fetches associated objects for 1:N associations (2nd direction)', function(done) { describe('hasOne with alias', function() {
this.User.hasMany(this.Task) before(function(done) {
this.Task.belongsTo(this.User) this.Worker.hasOne(this.Task, { as: 'ToDo' })
this.sequelize.sync({ force: true }).success(function() { this.sequelize.sync({ force: true }).complete(function() {
this.User.create({ name: 'barfooz' }).success(function(user) { this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'task1' }).success(function(task1) { this.Task.create({ title: 'homework' }).success(function(task) {
this.Task.create({ title: 'task2' }).success(function(task2) { this.worker = worker
user.setTasks([task1, task2]).success(function() { this.task = task
this.Task.findAll({
where: { 'Tasks.id': 1 }, this.worker.setToDo(this.task).success(done)
include: [ 'UserWithName' ] }.bind(this))
}).success(function(tasks) { }.bind(this))
expect(tasks[0].userWithName).toBeDefined() }.bind(this))
expect(tasks[0].userWithName.name).toEqual(user.name)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create it('throws an error if included DaoFactory is not referenced by alias', function() {
}.bind(this)) //- Task.create Helpers.assertException(function() {
}.bind(this)) //- User.create this.Worker.findAll({ include: [ this.Task ] })
}.bind(this)) //- sequelize.sync }.bind(this), 'Task is not associated to Worker!')
}) })
it('fetches associated objects for 1:N associations (2nd direction)', function(done) { it('throws an error if alias is not associated', function() {
this.User.hasMany(this.Task) Helpers.assertException(function() {
this.Task.belongsTo(this.User, { as: 'Owner' }) this.Worker.findAll({ include: [ { daoFactory: this.Task, as: 'Work' } ] })
}.bind(this), 'Task (Work) is not associated to Worker!')
})
this.sequelize.sync({ force: true }).success(function() { it('returns the associated task via worker.task', function(done) {
this.User.create({ name: 'barfooz' }).success(function(user) { this.Worker.findAll({
this.Task.create({ title: 'task1' }).success(function(task1) { where: { name: 'worker' },
this.Task.create({ title: 'task2' }).success(function(task2) { include: [ { daoFactory: this.Task, as: 'ToDo' } ]
user.setTasks([task1, task2]).success(function() { }).complete(function(err, workers) {
this.Task.findAll({ expect(err).toBeNull()
where: { 'Tasks.id': 1 }, expect(workers).toBeDefined()
include: [ 'Owner' ] expect(workers[0].toDo).toBeDefined()
}).success(function(tasks) { expect(workers[0].toDo.title).toEqual('homework')
expect(tasks[0].owner).toBeDefined()
expect(tasks[0].owner.name).toEqual(user.name)
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
}.bind(this)) //- Task.create this.Worker.findAll({
}.bind(this)) //- User.create where: { name: 'worker' },
}.bind(this)) //- sequelize.sync include: [ { model: this.Task, as: 'ToDo' } ]
}) }).complete(function(err, workers) {
expect(workers[0].toDo.title).toEqual('homework')
it('fetches associated objects for N:M associations (1st direction)', function(done) {
this.User.hasMany(this.Task)
this.Task.hasMany(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user1) {
this.Task.create({ title: 'task1' }).success(function(task1) {
this.Task.create({ title: 'task2' }).success(function(task2) {
user1.setTasks([task1, task2]).success(function() {
this.User.findAll({
where: { 'UserWithNames.id': user1.id },
include: [ 'Task' ]
}).success(function(users) {
expect(users[0].tasks).toBeDefined()
expect(
users[0].tasks.map(function(t) { return t.id })
).toEqual(
[ task1.id, task2.id ]
)
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create
}.bind(this)) //- sequelize.sync
})
it('fetches associated objects for N:M associations (1st direction)', function(done) {
this.User.hasMany(this.Task, { as: 'Homeworks' })
this.Task.hasMany(this.User)
this.sequelize.sync({ force: true }).success(function() {
this.User.create({ name: 'barfooz' }).success(function(user1) {
this.Task.create({ title: 'task1' }).success(function(task1) {
this.Task.create({ title: 'task2' }).success(function(task2) {
user1.setHomeworks([task1, task2]).success(function() {
this.User.findAll({
where: { 'UserWithNames.id': user1.id },
include: [ 'Homeworks' ]
}).success(function(users) {
expect(users[0].homeworks).toBeDefined()
expect(
users[0].homeworks.map(function(t) { return t.id })
).toEqual(
[ task1.id, task2.id ]
)
done()
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create describe('hasMany', function() {
}.bind(this)) //- sequelize.sync before(function(done) {
}) this.Worker.hasMany(this.Task)
it('fetches associated objects for N:M associations (2nd direction)', function(done) { this.sequelize.sync({ force: true }).complete(function() {
this.User.hasMany(this.Task) this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.hasMany(this.User) this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.sequelize.sync({ force: true }).success(function() { this.worker.setTasks([ this.task ]).success(done)
this.User.create({ name: 'barfooz' }).success(function(user1) { }.bind(this))
}.bind(this))
}.bind(this))
})
this.Task.create({ title: 'task1' }).success(function(task1) { it('throws an error if included DaoFactory is not associated', function() {
this.Task.create({ title: 'task2' }).success(function(task2) { Helpers.assertException(function() {
user1.setTasks([task1, task2]).success(function() { this.Task.findAll({ include: [ this.Worker ] })
this.Task.findAll({ }.bind(this), 'Worker is not associated to Task!')
where: { 'Tasks.id': task1.id }, })
include: [ 'UserWithName' ]
}).success(function(tasks) { it('returns the associated tasks via worker.tasks', function(done) {
expect(tasks[0].userWithNames).toBeDefined() this.Worker.findAll({
expect( where: { name: 'worker' },
tasks[0].userWithNames.map(function(u) { return u.id }) include: [ this.Task ]
).toEqual( }).complete(function(err, workers) {
[ user1.id ] expect(err).toBeNull()
) expect(workers).toBeDefined()
expect(workers[0].tasks).toBeDefined()
expect(workers[0].tasks[0].title).toEqual('homework')
done() done()
}.bind(this))
})
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create describe('hasMany with alias', function() {
}.bind(this)) //- sequelize.sync before(function(done) {
this.Worker.hasMany(this.Task, { as: 'ToDos' })
this.sequelize.sync({ force: true }).complete(function() {
this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.worker.setToDos([ this.task ]).success(done)
}.bind(this))
}.bind(this))
}.bind(this))
}) })
it('fetches associated objects for N:M associations (2nd direction)', function(done) { it('throws an error if included DaoFactory is not referenced by alias', function() {
this.User.hasMany(this.Task) Helpers.assertException(function() {
this.Task.hasMany(this.User, { as: 'Owners' }) this.Worker.findAll({ include: [ this.Task ] })
}.bind(this), 'Task is not associated to Worker!')
})
this.sequelize.sync({ force: true }).success(function() { it('throws an error if alias is not associated', function() {
this.User.create({ name: 'barfooz' }).success(function(user1) { Helpers.assertException(function() {
this.Worker.findAll({ include: [ { daoFactory: this.Task, as: 'Work' } ] })
}.bind(this), 'Task (Work) is not associated to Worker!')
})
this.Task.create({ title: 'task1' }).success(function(task1) { it('returns the associated task via worker.task', function(done) {
this.Task.create({ title: 'task2' }).success(function(task2) { this.Worker.findAll({
user1.setTasks([task1, task2]).success(function() { where: { name: 'worker' },
this.Task.findAll({ include: [ { daoFactory: this.Task, as: 'ToDos' } ]
where: { 'Tasks.id': task1.id }, }).complete(function(err, workers) {
include: [ 'Owners' ] expect(err).toBeNull()
}).success(function(tasks) { expect(workers).toBeDefined()
expect(tasks[0].owners).toBeDefined() expect(workers[0].toDos).toBeDefined()
expect( expect(workers[0].toDos[0].title).toEqual('homework')
tasks[0].owners.map(function(u) { return u.id })
).toEqual(
[ user1.id ]
)
done() done()
}.bind(this))
}) })
}.bind(this)) //- setTask
}.bind(this)) //- Task.create
}.bind(this)) //- Task.create
}.bind(this)) //- User.create it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
}.bind(this)) //- sequelize.sync this.Worker.findAll({
where: { name: 'worker' },
include: [ { daoFactory: this.Task, as: 'ToDos' } ]
}).complete(function(err, workers) {
expect(workers[0].toDos[0].title).toEqual('homework')
done()
}.bind(this))
})
}) })
}) })
}) //- describe: findAll }) //- describe: findAll
......
if(typeof require === 'function') { if (typeof require === 'function') {
const buster = require("buster") const buster = require("buster")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!