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

Commit 03f49f65 by Mick Hansen

Merge pull request #2240 from overlookmotel/hooks-options

Options passed to hooks
2 parents 87f1c86f b5f31a88
...@@ -5,10 +5,15 @@ ...@@ -5,10 +5,15 @@
- [FEATURE] Added `scope` to hasMany association definitions, provides default values to association setters/finders [#2268](https://github.com/sequelize/sequelize/pull/2268) - [FEATURE] Added `scope` to hasMany association definitions, provides default values to association setters/finders [#2268](https://github.com/sequelize/sequelize/pull/2268)
- [FEATURE] We now support transactions that automatically commit/rollback based on the result of the promise chain returned to the callback. - [FEATURE] We now support transactions that automatically commit/rollback based on the result of the promise chain returned to the callback.
- [BUG] Only try to create indexes which don't already exist. Closes [#2162](https://github.com/sequelize/sequelize/issues/2162) - [BUG] Only try to create indexes which don't already exist. Closes [#2162](https://github.com/sequelize/sequelize/issues/2162)
- [FEATURE] Hooks are passed options
- [FEATURE] Hooks need not return a result - undefined return is interpreted as a resolved promise
- [FEATURE] Added `find()` hooks
#### Backwards compatability changes #### Backwards compatability changes
- The `fieldName` property, used in associations with a foreign key object `(A.hasMany(B, { foreignKey: { ... }})`, has been renamed to `name` to avoid confusion with `field`. - The `fieldName` property, used in associations with a foreign key object `(A.hasMany(B, { foreignKey: { ... }})`, has been renamed to `name` to avoid confusion with `field`.
- The naming of the join table entry for N:M association getters is now singular (like includes) - The naming of the join table entry for N:M association getters is now singular (like includes)
- Signature of hooks has changed to pass options to all hooks
- Results returned by hooks are ignored - changes to results by hooks should be made by reference
# v2.0.0-dev13 # v2.0.0-dev13
We are working our way to the first 2.0.0 release candidate. We are working our way to the first 2.0.0 release candidate.
...@@ -18,9 +23,9 @@ We are working our way to the first 2.0.0 release candidate. ...@@ -18,9 +23,9 @@ We are working our way to the first 2.0.0 release candidate.
- [FEATURE] Added support for passing an `indexes` array in options to `sequelize.define`. [#1485](https://github.com/sequelize/sequelize/issues/1485). See API reference for details. - [FEATURE] Added support for passing an `indexes` array in options to `sequelize.define`. [#1485](https://github.com/sequelize/sequelize/issues/1485). See API reference for details.
- [FEATURE/INTERNALS] Standardized the output from `QueryInterface.showIndex`. - [FEATURE/INTERNALS] Standardized the output from `QueryInterface.showIndex`.
- [FEATURE] Include deleted rows in find [#2083](https://github.com/sequelize/sequelize/pull/2083) - [FEATURE] Include deleted rows in find [#2083](https://github.com/sequelize/sequelize/pull/2083)
- [FEATURE] Make addSingular and addPlural for n:m assocations (fx `addUser` and `addUsers` now both accept an array or an instance. - [FEATURE] Make addSingular and addPlural for n:m associations (fx `addUser` and `addUsers` now both accept an array or an instance.
- [BUG] Hid `dottie.transform` on raw queries behind a flag (`nest`) [#2064](https://github.com/sequelize/sequelize/pull/2064) - [BUG] Hid `dottie.transform` on raw queries behind a flag (`nest`) [#2064](https://github.com/sequelize/sequelize/pull/2064)
- [BUG] Fixed problems with transcation parameter being removed / not passed on in associations [#1789](https://github.com/sequelize/sequelize/issues/1789) and [#1968](https://github.com/sequelize/sequelize/issues/1968) - [BUG] Fixed problems with transaction parameter being removed / not passed on in associations [#1789](https://github.com/sequelize/sequelize/issues/1789) and [#1968](https://github.com/sequelize/sequelize/issues/1968)
- [BUG] Fix problem with minConnections. [#2048](https://github.com/sequelize/sequelize/issues/2048) - [BUG] Fix problem with minConnections. [#2048](https://github.com/sequelize/sequelize/issues/2048)
- [BUG] Fix default scope being overwritten [#2087](https://github.com/sequelize/sequelize/issues/2087) - [BUG] Fix default scope being overwritten [#2087](https://github.com/sequelize/sequelize/issues/2087)
- [BUG] Fixed updatedAt timestamp not being set in bulk create when validate = true. [#1962](https://github.com/sequelize/sequelize/issues/1962) - [BUG] Fixed updatedAt timestamp not being set in bulk create when validate = true. [#1962](https://github.com/sequelize/sequelize/issues/1962)
......
...@@ -35,9 +35,31 @@ var Utils = require('./utils') ...@@ -35,9 +35,31 @@ var Utils = require('./utils')
* @mixin Hooks * @mixin Hooks
*/ */
var Hooks = module.exports = function() {}; var Hooks = module.exports = function() {};
var hookTypes = {
beforeValidate: {params: 2},
afterValidate: {params: 2},
beforeCreate: {params: 2},
afterCreate: {params: 2},
beforeDestroy: {params: 2},
afterDestroy: {params: 2},
beforeUpdate: {params: 2},
afterUpdate: {params: 2},
beforeBulkCreate: {params: 2},
afterBulkCreate: {params: 2},
beforeBulkDestroy: {params: 1},
afterBulkDestroy: {params: 1},
beforeBulkUpdate: {params: 1},
afterBulkUpdate: {params: 1},
beforeFind: {params: 1},
beforeFindAfterExpandIncludeAll: {params: 1},
beforeFindAfterOptions: {params: 1},
afterFind: {params: 2}
};
var hookAliases = { var hookAliases = {
beforeDelete: 'beforeDestroy', beforeDelete: 'beforeDestroy',
afterDelete: 'afterDestroy' afterDelete: 'afterDestroy',
beforeBulkDelete: 'beforeBulkDestroy',
afterBulkDelete: 'afterBulkDestroy'
}; };
Hooks.replaceHookAliases = function(hooks) { Hooks.replaceHookAliases = function(hooks) {
...@@ -57,16 +79,18 @@ Hooks.replaceHookAliases = function(hooks) { ...@@ -57,16 +79,18 @@ Hooks.replaceHookAliases = function(hooks) {
return hooks; return hooks;
}; };
Hooks.runHooks = function() { Hooks.runHooks = function(hooks) {
var self = this var self = this
, tick = 0 , fn
, hooks = arguments[0] , fnArgs = Array.prototype.slice.call(arguments, 1)
, lastIndex = arguments.length - 1 , hookType;
, fn = typeof arguments[lastIndex] === 'function' ? arguments[lastIndex] : null
, fnArgs = Array.prototype.slice.call(arguments, 1, fn ? lastIndex : arguments.length) if (typeof fnArgs[fnArgs.length - 1] === 'function') {
, resolveArgs = fnArgs; fn = fnArgs.pop();
}
if (typeof hooks === 'string') { if (typeof hooks === 'string') {
hookType = hooks;
hooks = this.options.hooks[hooks] || []; hooks = this.options.hooks[hooks] || [];
} }
...@@ -74,53 +98,20 @@ Hooks.runHooks = function() { ...@@ -74,53 +98,20 @@ Hooks.runHooks = function() {
hooks = hooks === undefined ? [] : [hooks]; hooks = hooks === undefined ? [] : [hooks];
} }
var promise = new Promise(function(resolve, reject) { var promise = Promise.map(hooks, function(hook) {
if (hooks.length < 1) {
return resolve(fnArgs);
}
var run = function(hook) {
if (!hook) {
return resolve(resolveArgs);
}
if (typeof hook === 'object') { if (typeof hook === 'object') {
hook = hook.fn; hook = hook.fn;
} }
var maybePromise = hook.apply(self, fnArgs.concat(function() { if (hookType && hook.length > hookTypes[hookType].params) {
tick++; hook = Promise.promisify(hook, self);
if (!!arguments[0]) {
return reject(arguments[0]);
}
if (arguments.length) {
resolveArgs = Array.prototype.slice.call(arguments, 1);
}
return run(hooks[tick]);
}));
if (Utils.Promise.is(maybePromise)) {
maybePromise.spread(function() {
tick++;
if (arguments.length) {
resolveArgs = Array.prototype.slice.call(arguments);
}
return run(hooks[tick]);
}, reject);
} }
};
run(hooks[tick]); return hook.apply(self, fnArgs);
}); }, {concurrency: 1}).return();
if (fn) { if (fn) {
promise = promise.spread(function() { return promise.nodeify(fn);
fn.apply(self, [null].concat(Array.prototype.slice.apply(arguments)));
}, fn);
} }
return promise; return promise;
...@@ -145,23 +136,19 @@ Hooks.addHook = function(hookType, name, fn) { ...@@ -145,23 +136,19 @@ Hooks.addHook = function(hookType, name, fn) {
name = null; name = null;
} }
var method = function() {
return fn.apply(this, Array.prototype.slice.call(arguments, 0, arguments.length - 1).concat(arguments[arguments.length - 1]));
};
// Aliases // Aliases
hookType = hookAliases[hookType] || hookType; hookType = hookAliases[hookType] || hookType;
// Just in case if we override the default DAOFactory.options // Just in case if we override the default DAOFactory.options
this.options.hooks[hookType] = this.options.hooks[hookType] || []; this.options.hooks[hookType] = this.options.hooks[hookType] || [];
this.options.hooks[hookType][this.options.hooks[hookType].length] = !!name ? {name: name, fn: method} : method; this.options.hooks[hookType][this.options.hooks[hookType].length] = !!name ? {name: name, fn: fn} : fn;
return this; return this;
}; };
/** /**
* A hook that is run before validation * A hook that is run before validation
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err) * @param {Function} fn A callback function that is called with instance, options, callback(err)
*/ */
Hooks.beforeValidate = function(name, fn) { Hooks.beforeValidate = function(name, fn) {
return Hooks.addHook.call(this, 'beforeValidate', name, fn); return Hooks.addHook.call(this, 'beforeValidate', name, fn);
...@@ -170,7 +157,7 @@ Hooks.beforeValidate = function(name, fn) { ...@@ -170,7 +157,7 @@ Hooks.beforeValidate = function(name, fn) {
/** /**
* A hook that is run after validation * A hook that is run after validation
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err) * @param {Function} fn A callback function that is called with instance, options, callback(err)
*/ */
Hooks.afterValidate = function(name, fn) { Hooks.afterValidate = function(name, fn) {
return Hooks.addHook.call(this, 'afterValidate', name, fn); return Hooks.addHook.call(this, 'afterValidate', name, fn);
...@@ -179,7 +166,7 @@ Hooks.afterValidate = function(name, fn) { ...@@ -179,7 +166,7 @@ Hooks.afterValidate = function(name, fn) {
/** /**
* A hook that is run before creating a single instance * A hook that is run before creating a single instance
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with attributes, callback(err) * @param {Function} fn A callback function that is called with attributes, options, callback(err)
*/ */
Hooks.beforeCreate = function(name, fn) { Hooks.beforeCreate = function(name, fn) {
return Hooks.addHook.call(this, 'beforeCreate', name, fn); return Hooks.addHook.call(this, 'beforeCreate', name, fn);
...@@ -188,7 +175,7 @@ Hooks.beforeCreate = function(name, fn) { ...@@ -188,7 +175,7 @@ Hooks.beforeCreate = function(name, fn) {
/** /**
* A hook that is run after creating a single instance * A hook that is run after creating a single instance
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with attributes, callback(err) * @param {Function} fn A callback function that is called with attributes, options, callback(err)
*/ */
Hooks.afterCreate = function(name, fn) { Hooks.afterCreate = function(name, fn) {
return Hooks.addHook.call(this, 'afterCreate', name, fn); return Hooks.addHook.call(this, 'afterCreate', name, fn);
...@@ -197,7 +184,7 @@ Hooks.afterCreate = function(name, fn) { ...@@ -197,7 +184,7 @@ Hooks.afterCreate = function(name, fn) {
/** /**
* A hook that is run before destroying a single instance * A hook that is run before destroying a single instance
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err) * @param {Function} fn A callback function that is called with instance, options, callback(err)
* *
* @alias beforeDelete * @alias beforeDelete
*/ */
...@@ -205,10 +192,14 @@ Hooks.beforeDestroy = function(name, fn) { ...@@ -205,10 +192,14 @@ Hooks.beforeDestroy = function(name, fn) {
return Hooks.addHook.call(this, 'beforeDestroy', name, fn); return Hooks.addHook.call(this, 'beforeDestroy', name, fn);
}; };
Hooks.beforeDelete = function(name, fn) {
return Hooks.addHook.call(this, 'beforeDelete', name, fn);
};
/** /**
* A hook that is run after destroying a single instance * A hook that is run after destroying a single instance
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err) * @param {Function} fn A callback function that is called with instance, options, callback(err)
* *
* @alias afterDelete * @alias afterDelete
*/ */
...@@ -216,10 +207,6 @@ Hooks.afterDestroy = function(name, fn) { ...@@ -216,10 +207,6 @@ Hooks.afterDestroy = function(name, fn) {
return Hooks.addHook.call(this, 'afterDestroy', name, fn); return Hooks.addHook.call(this, 'afterDestroy', name, fn);
}; };
Hooks.beforeDelete = function(name, fn) {
return Hooks.addHook.call(this, 'beforeDelete', name, fn);
};
Hooks.afterDelete = function(name, fn) { Hooks.afterDelete = function(name, fn) {
return Hooks.addHook.call(this, 'afterDelete', name, fn); return Hooks.addHook.call(this, 'afterDelete', name, fn);
}; };
...@@ -227,7 +214,7 @@ Hooks.afterDelete = function(name, fn) { ...@@ -227,7 +214,7 @@ Hooks.afterDelete = function(name, fn) {
/** /**
* A hook that is run before updating a single instance * A hook that is run before updating a single instance
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err) * @param {Function} fn A callback function that is called with instance, options, callback(err)
*/ */
Hooks.beforeUpdate = function(name, fn) { Hooks.beforeUpdate = function(name, fn) {
return Hooks.addHook.call(this, 'beforeUpdate', name, fn); return Hooks.addHook.call(this, 'beforeUpdate', name, fn);
...@@ -236,7 +223,7 @@ Hooks.beforeUpdate = function(name, fn) { ...@@ -236,7 +223,7 @@ Hooks.beforeUpdate = function(name, fn) {
/** /**
* A hook that is run after updating a single instance * A hook that is run after updating a single instance
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instance, callback(err) * @param {Function} fn A callback function that is called with instance, options, callback(err)
*/ */
Hooks.afterUpdate = function(name, fn) { Hooks.afterUpdate = function(name, fn) {
return Hooks.addHook.call(this, 'afterUpdate', name, fn); return Hooks.addHook.call(this, 'afterUpdate', name, fn);
...@@ -245,7 +232,7 @@ Hooks.afterUpdate = function(name, fn) { ...@@ -245,7 +232,7 @@ Hooks.afterUpdate = function(name, fn) {
/** /**
* A hook that is run before creating instances in bulk * A hook that is run before creating instances in bulk
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instances, fields, callback(err) * @param {Function} fn A callback function that is called with instances, options, callback(err)
*/ */
Hooks.beforeBulkCreate = function(name, fn) { Hooks.beforeBulkCreate = function(name, fn) {
return Hooks.addHook.call(this, 'beforeBulkCreate', name, fn); return Hooks.addHook.call(this, 'beforeBulkCreate', name, fn);
...@@ -254,34 +241,46 @@ Hooks.beforeBulkCreate = function(name, fn) { ...@@ -254,34 +241,46 @@ Hooks.beforeBulkCreate = function(name, fn) {
/** /**
* A hook that is run after creating instances in bulk * A hook that is run after creating instances in bulk
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with instances, fields, callback(err) * @param {Function} fn A callback function that is called with instances, options, callback(err)
*/ */
Hooks.afterBulkCreate = function(name, fn) { Hooks.afterBulkCreate = function(name, fn) {
return Hooks.addHook.call(this, 'afterBulkCreate', name, fn); return Hooks.addHook.call(this, 'afterBulkCreate', name, fn);
}; };
/** /**
* A hook that is run before destroing instances in bulk * A hook that is run before destroying instances in bulk
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with where, callback(err) * @param {Function} fn A callback function that is called with options, callback(err)
*
* @alias beforeBulkDelete
*/ */
Hooks.beforeBulkDestroy = function(name, fn) { Hooks.beforeBulkDestroy = function(name, fn) {
return Hooks.addHook.call(this, 'beforeBulkDestroy', name, fn); return Hooks.addHook.call(this, 'beforeBulkDestroy', name, fn);
}; };
Hooks.beforeBulkDelete = function(name, fn) {
return Hooks.addHook.call(this, 'beforeBulkDelete', name, fn);
};
/** /**
* A hook that is run after destroying instances in bulk * A hook that is run after destroying instances in bulk
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with where, callback(err) * @param {Function} fn A callback function that is called with options, callback(err)
*
* @alias afterBulkDelete
*/ */
Hooks.afterBulkDestroy = function(name, fn) { Hooks.afterBulkDestroy = function(name, fn) {
return Hooks.addHook.call(this, 'afterBulkDestroy', name, fn); return Hooks.addHook.call(this, 'afterBulkDestroy', name, fn);
}; };
Hooks.afterBulkDelete = function(name, fn) {
return Hooks.addHook.call(this, 'afterBulkDelete', name, fn);
};
/** /**
* A hook that is run after updating instances in bulk * A hook that is run after updating instances in bulk
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with attribute, where, callback(err) * @param {Function} fn A callback function that is called with options, callback(err)
*/ */
Hooks.beforeBulkUpdate = function(name, fn) { Hooks.beforeBulkUpdate = function(name, fn) {
return Hooks.addHook.call(this, 'beforeBulkUpdate', name, fn); return Hooks.addHook.call(this, 'beforeBulkUpdate', name, fn);
...@@ -290,8 +289,44 @@ Hooks.beforeBulkUpdate = function(name, fn) { ...@@ -290,8 +289,44 @@ Hooks.beforeBulkUpdate = function(name, fn) {
/** /**
* A hook that is run after updating instances in bulk * A hook that is run after updating instances in bulk
* @param {String} name * @param {String} name
* @param {Function} fn A callback function that is called with attribute, where, callback(err) * @param {Function} fn A callback function that is called with options, callback(err)
*/ */
Hooks.afterBulkUpdate = function(name, fn) { Hooks.afterBulkUpdate = function(name, fn) {
return Hooks.addHook.call(this, 'afterBulkUpdate', name, fn); return Hooks.addHook.call(this, 'afterBulkUpdate', name, fn);
}; };
/**
* A hook that is run before a find (select) query
* @param {String} name
* @param {Function} fn A callback function that is called with options, callback(err)
*/
Hooks.beforeFind = function(name, fn) {
return Hooks.addHook.call(this, 'beforeFind', name, fn);
};
/**
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
* @param {String} name
* @param {Function} fn A callback function that is called with options, callback(err)
*/
Hooks.beforeFindAfterExpandIncludeAll = function(name, fn) {
return Hooks.addHook.call(this, 'beforeFindAfterExpandIncludeAll', name, fn);
};
/**
* A hook that is run before a find (select) query, after all option parsing is complete
* @param {String} name
* @param {Function} fn A callback function that is called with options, callback(err)
*/
Hooks.beforeFindAfterOptions = function(name, fn) {
return Hooks.addHook.call(this, 'beforeFindAfterOptions', name, fn);
};
/**
* A hook that is run after a find (select) query
* @param {String} name
* @param {Function} fn A callback function that is called with instance(s), options, callback(err)
*/
Hooks.afterFind = function(name, fn) {
return Hooks.addHook.call(this, 'afterFind', name, fn);
};
...@@ -165,14 +165,14 @@ InstanceValidator.prototype.validate = function() { ...@@ -165,14 +165,14 @@ InstanceValidator.prototype.validate = function() {
*/ */
InstanceValidator.prototype.hookValidate = function() { InstanceValidator.prototype.hookValidate = function() {
var self = this; var self = this;
return self.modelInstance.Model.runHooks('beforeValidate', self.modelInstance).then(function() { return self.modelInstance.Model.runHooks('beforeValidate', self.modelInstance, self.options).then(function() {
return self.validate().then(function(error) { return self.validate().then(function(error) {
if (error) { if (error) {
throw error; throw error;
} }
}); });
}).then(function() { }).then(function() {
return self.modelInstance.Model.runHooks('afterValidate', self.modelInstance); return self.modelInstance.Model.runHooks('afterValidate', self.modelInstance, self.options);
}).return(self.modelInstance); }).return(self.modelInstance);
}; };
......
...@@ -495,7 +495,10 @@ module.exports = (function() { ...@@ -495,7 +495,10 @@ module.exports = (function() {
return Promise.try(function() { return Promise.try(function() {
// Validate // Validate
if (options.hooks) { if (options.hooks) {
return self.hookValidate({skip: _.difference(Object.keys(self.rawAttributes), options.fields)}); options.skip = _.difference(Object.keys(self.rawAttributes), options.fields);
return self.hookValidate(options).then(function() {
delete options.skip;
});
} }
}).then(function() { }).then(function() {
options.fields.forEach(function(field) { options.fields.forEach(function(field) {
...@@ -584,7 +587,7 @@ module.exports = (function() { ...@@ -584,7 +587,7 @@ module.exports = (function() {
return Promise.try(function() { return Promise.try(function() {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return self.Model.runHooks('before' + hook, self).then(function() { return self.Model.runHooks('before' + hook, self, options).then(function() {
// dataValues might have changed inside the hook, rebuild the values hash // dataValues might have changed inside the hook, rebuild the values hash
values = {}; values = {};
...@@ -634,7 +637,7 @@ module.exports = (function() { ...@@ -634,7 +637,7 @@ module.exports = (function() {
}).tap(function(result) { }).tap(function(result) {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.Model.runHooks('after' + hook, result); return self.Model.runHooks('after' + hook, result, options);
} }
}).then(function(result) { }).then(function(result) {
return result; return result;
...@@ -683,8 +686,8 @@ module.exports = (function() { ...@@ -683,8 +686,8 @@ module.exports = (function() {
return new InstanceValidator(this, options).validate(); return new InstanceValidator(this, options).validate();
}; };
Instance.prototype.hookValidate = function(object) { Instance.prototype.hookValidate = function(options) {
var validator = new InstanceValidator(this, object); var validator = new InstanceValidator(this, options);
return validator.hookValidate(); return validator.hookValidate();
}; };
...@@ -732,7 +735,7 @@ module.exports = (function() { ...@@ -732,7 +735,7 @@ module.exports = (function() {
return Promise.try(function() { return Promise.try(function() {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return self.Model.runHooks('beforeDestroy', self); return self.Model.runHooks('beforeDestroy', self, options);
} }
}).then(function() { }).then(function() {
var identifier; var identifier;
...@@ -747,7 +750,7 @@ module.exports = (function() { ...@@ -747,7 +750,7 @@ module.exports = (function() {
}).tap(function(result) { }).tap(function(result) {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.Model.runHooks('afterDestroy', self); return self.Model.runHooks('afterDestroy', self, options);
} }
}).then(function(result) { }).then(function(result) {
return result; return result;
......
...@@ -693,8 +693,25 @@ module.exports = (function() { ...@@ -693,8 +693,25 @@ module.exports = (function() {
tableNames[this.getTableName()] = true; tableNames[this.getTableName()] = true;
options = optClone(options || {}); options = optClone(options || {});
options = Utils._.defaults(options, {
hooks: true
});
return Promise.bind(this).then(function() {
conformOptions(options);
if (options.hooks) {
return this.runHooks('beforeFind', options);
}
}).then(function() {
expandIncludeAll.call(this, options);
if (options.hooks) {
return this.runHooks('beforeFindAfterExpandIncludeAll', options);
}
}).then(function() {
if (typeof options === 'object') { if (typeof options === 'object') {
if (options.hasOwnProperty('include') && options.include) { if (options.include) {
hasJoin = true; hasJoin = true;
validateIncludedElements.call(this, options, tableNames); validateIncludedElements.call(this, options, tableNames);
...@@ -718,11 +735,20 @@ module.exports = (function() { ...@@ -718,11 +735,20 @@ module.exports = (function() {
options = paranoidClause.call(this, options); options = paranoidClause.call(this, options);
if (options.hooks) {
return this.runHooks('beforeFindAfterOptions', options);
}
}).then(function() {
return this.QueryInterface.select(this, this.getTableName(), options, Utils._.defaults({ return this.QueryInterface.select(this, this.getTableName(), options, Utils._.defaults({
type: QueryTypes.SELECT, type: QueryTypes.SELECT,
hasJoin: hasJoin, hasJoin: hasJoin,
tableNames: Object.keys(tableNames) tableNames: Object.keys(tableNames)
}, queryOptions, { transaction: (options || {}).transaction })); }, queryOptions, { transaction: (options || {}).transaction }));
}).tap(function(results) {
if (options.hooks) {
return this.runHooks('afterFind', results, options);
}
});
}; };
//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
...@@ -818,10 +844,12 @@ module.exports = (function() { ...@@ -818,10 +844,12 @@ module.exports = (function() {
*/ */
Model.prototype.count = function(options) { Model.prototype.count = function(options) {
options = Utils._.clone(options || {}); options = Utils._.clone(options || {});
conformOptions(options);
var col = '*'; var col = '*';
if (options.include) { if (options.include) {
col = this.name + '.' + this.primaryKeyAttribute; col = this.name + '.' + this.primaryKeyAttribute;
expandIncludeAll.call(this, options);
validateIncludedElements.call(this, options); validateIncludedElements.call(this, options);
} }
...@@ -935,9 +963,13 @@ module.exports = (function() { ...@@ -935,9 +963,13 @@ module.exports = (function() {
}); });
} }
if (options.hasOwnProperty('include') && options.include && !options.includeValidated) { if (!options.includeValidated) {
conformOptions(options);
if (options.include) {
expandIncludeAll.call(this, options);
validateIncludedElements.call(this, options); validateIncludedElements.call(this, options);
} }
}
return new this.Instance(values, options); return new this.Instance(values, options);
}; };
...@@ -946,9 +978,13 @@ module.exports = (function() { ...@@ -946,9 +978,13 @@ module.exports = (function() {
Model.prototype.bulkBuild = function(valueSets, options) { Model.prototype.bulkBuild = function(valueSets, options) {
options = options || { isNewRecord: true, isDirty: true }; options = options || { isNewRecord: true, isDirty: true };
if (options.hasOwnProperty('include') && options.include && !options.includeValidated) { if (!options.includeValidated) {
conformOptions(options);
if (options.include) {
expandIncludeAll.call(this, options);
validateIncludedElements.call(this, options); validateIncludedElements.call(this, options);
} }
}
if (options.attributes) { if (options.attributes) {
options.attributes = options.attributes.map(function(attribute) { options.attributes = options.attributes.map(function(attribute) {
...@@ -1033,7 +1069,9 @@ module.exports = (function() { ...@@ -1033,7 +1069,9 @@ module.exports = (function() {
var build = self.build(params); var build = self.build(params);
return build.hookValidate({skip: Object.keys(params)}).then(function() { options.skip = Object.keys(params);
return build.hookValidate(options).then(function() {
delete options.skip;
return Promise.resolve([build, true]); return Promise.resolve([build, true]);
}); });
} }
...@@ -1170,10 +1208,7 @@ module.exports = (function() { ...@@ -1170,10 +1208,7 @@ module.exports = (function() {
return Promise.try(function() { return Promise.try(function() {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('beforeBulkCreate', daos, options.fields).spread(function(_daos, _fields) { return self.runHooks('beforeBulkCreate', daos, options);
daos = _daos || daos;
options.fields = _fields || options.fields;
});
} }
}).then(function() { }).then(function() {
daos.forEach(function(dao) { daos.forEach(function(dao) {
...@@ -1196,17 +1231,18 @@ module.exports = (function() { ...@@ -1196,17 +1231,18 @@ module.exports = (function() {
// Validate // Validate
if (options.validate) { if (options.validate) {
var skippedFields = Utils._.difference(Object.keys(self.attributes), options.fields); options.skip = Utils._.difference(Object.keys(self.attributes), options.fields);
var errors = []; var errors = [];
return Promise.map(daos, function(dao) { return Promise.map(daos, function(dao) {
var fn = options.individualHooks ? 'hookValidate' : 'validate'; var fn = options.individualHooks ? 'hookValidate' : 'validate';
return dao[fn]({skip: skippedFields}).then(function(err) { return dao[fn](options).then(function(err) {
if (!!err) { if (!!err) {
errors.push({record: dao, errors: err}); errors.push({record: dao, errors: err});
} }
}); });
}).then(function() { }).then(function() {
delete options.skip;
if (errors.length) { if (errors.length) {
return Promise.reject(errors); return Promise.reject(errors);
} }
...@@ -1216,7 +1252,14 @@ module.exports = (function() { ...@@ -1216,7 +1252,14 @@ module.exports = (function() {
if (options.individualHooks) { if (options.individualHooks) {
// Create each dao individually // Create each dao individually
return Promise.map(daos, function(dao) { return Promise.map(daos, function(dao) {
return dao.save({transaction: options.transaction}); var individualOptions = Utils._.clone(options);
delete individualOptions.fields;
delete individualOptions.individualHooks;
delete individualOptions.ignoreDuplicates;
individualOptions.validate = false;
individualOptions.hooks = true;
return dao.save(individualOptions);
}).then(function(_daos) { }).then(function(_daos) {
daos = _daos; daos = _daos;
}); });
...@@ -1254,9 +1297,7 @@ module.exports = (function() { ...@@ -1254,9 +1297,7 @@ module.exports = (function() {
}).then(function() { }).then(function() {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('afterBulkCreate', daos, options.fields).spread(function(_daos) { return self.runHooks('afterBulkCreate', daos, options);
if (_daos) daos = _daos;
});
} }
}).then(function() { }).then(function() {
return daos; return daos;
...@@ -1293,16 +1334,18 @@ module.exports = (function() { ...@@ -1293,16 +1334,18 @@ module.exports = (function() {
return Promise.try(function() { return Promise.try(function() {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('beforeBulkDestroy', where).spread(function(_where) { options.where = where;
where = _where || where; return self.runHooks('beforeBulkDestroy', options).then(function() {
where = options.where;
delete options.where;
}); });
} }
}).then(function() { }).then(function() {
// Get daos and run beforeDestroy hook on each record individually // Get daos and run beforeDestroy hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return self.all({where: where}, {transaction: options.transaction}).map(function(dao) { return self.findAll({where: where}, {transaction: options.transaction}).map(function(dao) {
return self.runHooks('beforeDestroy', dao).spread(function(_dao) { return self.runHooks('beforeDestroy', dao, options).then(function() {
return _dao || dao; return dao;
}); });
}).then(function(_daos) { }).then(function(_daos) {
daos = _daos; daos = _daos;
...@@ -1321,13 +1364,16 @@ module.exports = (function() { ...@@ -1321,13 +1364,16 @@ module.exports = (function() {
// Run afterDestroy hook on each record individually // Run afterDestroy hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return Promise.map(daos, function(dao) { return Promise.map(daos, function(dao) {
return self.runHooks('afterDestroy', dao); return self.runHooks('afterDestroy', dao, options);
}); });
} }
}).tap(function() { }).tap(function() {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('afterBulkDestroy', where); options.where = where;
return self.runHooks('afterBulkDestroy', options).then(function() {
delete options.where;
});
} }
}).then(function(affectedRows) { }).then(function(affectedRows) {
return affectedRows; return affectedRows;
...@@ -1377,8 +1423,9 @@ module.exports = (function() { ...@@ -1377,8 +1423,9 @@ module.exports = (function() {
build.set(self._timestampAttributes.updatedAt, attrValueHash[self._timestampAttributes.updatedAt], { raw: true }); build.set(self._timestampAttributes.updatedAt, attrValueHash[self._timestampAttributes.updatedAt], { raw: true });
// We want to skip validations for all other fields // We want to skip validations for all other fields
var skippedFields = Utils._.difference(Object.keys(self.attributes), Object.keys(attrValueHash)); options.skip = Utils._.difference(Object.keys(self.attributes), Object.keys(attrValueHash));
return build.hookValidate({skip: skippedFields}).then(function(attributes) { return build.hookValidate(options).then(function(attributes) {
delete options.skip;
if (attributes && attributes.dataValues) { if (attributes && attributes.dataValues) {
attrValueHash = Utils._.pick(attributes.dataValues, Object.keys(attrValueHash)); attrValueHash = Utils._.pick(attributes.dataValues, Object.keys(attrValueHash));
} }
...@@ -1387,9 +1434,13 @@ module.exports = (function() { ...@@ -1387,9 +1434,13 @@ module.exports = (function() {
}).then(function() { }).then(function() {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('beforeBulkUpdate', attrValueHash, where).spread(function(_attrValueHash, _where) { options.where = where;
where = _where || where; options.attributes = attrValueHash;
attrValueHash = _attrValueHash || attrValueHash; return self.runHooks('beforeBulkUpdate', options).then(function() {
where = options.where;
attrValueHash = options.attributes;
delete options.where;
delete options.attributes;
}); });
} }
}).then(function() { }).then(function() {
...@@ -1397,7 +1448,7 @@ module.exports = (function() { ...@@ -1397,7 +1448,7 @@ module.exports = (function() {
// Get daos and run beforeUpdate hook on each record individually // Get daos and run beforeUpdate hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return self.all({where: where}, {transaction: options.transaction}).then(function(_daos) { return self.findAll({where: where}, {transaction: options.transaction}).then(function(_daos) {
daos = _daos; daos = _daos;
if (!daos.length) { if (!daos.length) {
return []; return [];
...@@ -1413,9 +1464,7 @@ module.exports = (function() { ...@@ -1413,9 +1464,7 @@ module.exports = (function() {
Utils._.extend(dao.dataValues, attrValueHash); Utils._.extend(dao.dataValues, attrValueHash);
// Run beforeUpdate hook // Run beforeUpdate hook
return self.runHooks('beforeUpdate', dao).spread(function(_dao) { return self.runHooks('beforeUpdate', dao, options).then(function() {
dao = _dao || dao;
if (!different) { if (!different) {
var thisChangedValues = {}; var thisChangedValues = {};
Utils._.forIn(dao.dataValues, function(newValue, attr) { Utils._.forIn(dao.dataValues, function(newValue, attr) {
...@@ -1447,7 +1496,12 @@ module.exports = (function() { ...@@ -1447,7 +1496,12 @@ module.exports = (function() {
// Hooks change values in a different way for each record // Hooks change values in a different way for each record
// Do not run original query but save each record individually // Do not run original query but save each record individually
return Promise.map(daos, function(dao) { return Promise.map(daos, function(dao) {
return dao.save({transaction: options.transaction, hooks: false}); var individualOptions = Utils._.clone(options);
delete individualOptions.individualHooks;
individualOptions.hooks = false;
individualOptions.validate = false;
return dao.save(individualOptions);
}).tap(function(_daos) { }).tap(function(_daos) {
daos = _daos; daos = _daos;
}); });
...@@ -1464,6 +1518,7 @@ module.exports = (function() { ...@@ -1464,6 +1518,7 @@ module.exports = (function() {
// Run query to update all rows // Run query to update all rows
return self.QueryInterface.bulkUpdate(self.getTableName(), attrValueHashUse, where, options, self.tableAttributes).then(function(affectedRows) { return self.QueryInterface.bulkUpdate(self.getTableName(), attrValueHashUse, where, options, self.tableAttributes).then(function(affectedRows) {
if (options.returning) { if (options.returning) {
daos = affectedRows;
return [affectedRows.length, affectedRows]; return [affectedRows.length, affectedRows];
} }
...@@ -1472,17 +1527,20 @@ module.exports = (function() { ...@@ -1472,17 +1527,20 @@ module.exports = (function() {
}).tap(function(result) { }).tap(function(result) {
if (options.individualHooks) { if (options.individualHooks) {
return Promise.map(daos, function(dao) { return Promise.map(daos, function(dao) {
return self.runHooks('afterUpdate', dao).spread(function(_dao) { return self.runHooks('afterUpdate', dao, options);
return _dao || dao; }).then(function() {
}); result[1] = daos;
}).then(function(_daos) {
result[1] = daos = _daos;
}); });
} }
}).tap(function() { }).tap(function() {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('afterBulkUpdate', attrValueHash, where); options.where = where;
options.attributes = attrValueHash;
return self.runHooks('afterBulkUpdate', options).then(function() {
delete options.where;
delete options.attributes;
});
} }
}).then(function(result) { }).then(function(result) {
// Return result in form [affectedRows, daos] (daos missed off if options.individualHooks != true) // Return result in form [affectedRows, daos] (daos missed off if options.individualHooks != true)
...@@ -1681,46 +1739,52 @@ module.exports = (function() { ...@@ -1681,46 +1739,52 @@ module.exports = (function() {
}.bind(this)); }.bind(this));
}; };
var validateIncludedElements = function(options, tableNames) { var conformOptions = function(options) {
tableNames = tableNames || {}; if (!options.include) {
options.includeNames = []; return;
options.includeMap = {}; }
options.hasSingleAssociation = false;
options.hasMultiAssociation = false;
// if include is not an array, wrap in an array // if include is not an array, wrap in an array
if (!Array.isArray(options.include)) { if (!Array.isArray(options.include)) {
options.include = [options.include]; options.include = [options.include];
} else if (!options.include.length) {
delete options.include;
return;
} }
// convert all included elements to { Model: Model } form // convert all included elements to { model: Model } form
var includes = options.include = options.include.map(function(include) { options.include = options.include.map(function(include) {
if (include instanceof Association) { if (include instanceof Association) {
include = { association: include }; include = { association: include };
} else if (include instanceof Model) { } else if (include instanceof Model) {
include = { model: include }; include = { model: include };
} else if (typeof include !== 'object') { } else if (typeof include !== 'object') {
throw new Error('Include unexpected. Element has to be either a Model, an Association or an object.'); throw new Error('Include unexpected. Element has to be either a Model, an Association or an object.');
} else if (include.hasOwnProperty('daoFactory')) { } else {
// convert daoFactory to model (for backwards compatibility)
if (include.hasOwnProperty('daoFactory')) {
include.model = include.daoFactory; include.model = include.daoFactory;
delete include.daoFactory;
}
conformOptions(include);
} }
return include; return include;
}); });
};
var validateIncludedElements = function(options, tableNames) {
tableNames = tableNames || {};
options.includeNames = [];
options.includeMap = {};
options.hasSingleAssociation = false;
options.hasMultiAssociation = false;
// validate all included elements // validate all included elements
var includes = options.include;
for (var index = 0; index < includes.length; index++) { for (var index = 0; index < includes.length; index++) {
var include = includes[index]; var include = includes[index] = validateIncludedElement.call(this, includes[index], tableNames);
if (include.all) {
includes.splice(index, 1);
index--;
validateIncludedAllElement.call(this, includes, include);
continue;
}
include = includes[index] = validateIncludedElement.call(this, include, tableNames);
include.parent = options; include.parent = options;
// associations that are required or have a required child as is not a ?:M association are candidates for the subquery // associations that are required or have a required child as is not a ?:M association are candidates for the subquery
...@@ -1742,7 +1806,6 @@ module.exports = (function() { ...@@ -1742,7 +1806,6 @@ module.exports = (function() {
options.hasIncludeRequired = options.hasIncludeRequired || include.hasIncludeRequired || !!include.required; options.hasIncludeRequired = options.hasIncludeRequired || include.hasIncludeRequired || !!include.required;
} }
}; };
Model.$validateIncludedElements = validateIncludedElements;
var validateIncludedElement = function(include, tableNames) { var validateIncludedElement = function(include, tableNames) {
if (!include.hasOwnProperty('model') && !include.hasOwnProperty('association')) { if (!include.hasOwnProperty('model') && !include.hasOwnProperty('association')) {
...@@ -1822,7 +1885,29 @@ module.exports = (function() { ...@@ -1822,7 +1885,29 @@ module.exports = (function() {
} }
}; };
var validateIncludedAllElement = function(includes, include) { var expandIncludeAll = function(options) {
var includes = options.include;
if (!includes) {
return;
}
for (var index = 0; index < includes.length; index++) {
var include = includes[index];
if (include.all) {
includes.splice(index, 1);
index--;
expandIncludeAllElement.call(this, includes, include);
}
}
Utils._.forEach(includes, function(include) {
expandIncludeAll.call(include.model, include);
});
};
var expandIncludeAllElement = function(includes, include) {
// check 'all' attribute provided is valid // check 'all' attribute provided is valid
var all = include.all; var all = include.all;
delete include.all; delete include.all;
......
...@@ -332,19 +332,19 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -332,19 +332,19 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
describe('generic', function() { describe('generic', function() {
it('throws an error about unexpected input if include contains a non-object', function(done) { it('throws an error about unexpected input if include contains a non-object', function(done) {
var self = this var self = this
expect(function() { self.Worker.find({ include: [ 1 ] }).catch(function(err) {
self.Worker.find({ include: [ 1 ] }) expect(err.message).to.equal('Include unexpected. Element has to be either a Model, an Association or an object.');
}).to.throw(Error)
done() done()
}) })
})
it('throws an error if included DaoFactory is not associated', function(done) { it('throws an error if included DaoFactory is not associated', function(done) {
var self = this var self = this
expect(function() { self.Worker.find({ include: [ self.Task ] }).catch(function(err) {
self.Worker.find({ include: [ self.Task ] }) expect(err.message).to.equal('Task is not associated to Worker!');
}).to.throw(Error, 'Task is not associated to Worker!')
done() done()
}) })
})
it('returns the associated worker via task.worker', function(done) { it('returns the associated worker via task.worker', function(done) {
var self = this var self = this
...@@ -518,11 +518,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -518,11 +518,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error if included DaoFactory is not associated', function(done) { it('throws an error if included DaoFactory is not associated', function(done) {
var self = this var self = this
expect(function() { self.Task.find({ include: [ self.Worker ] }).catch(function(err) {
self.Task.find({ include: [ self.Worker ] }) expect(err.message).to.equal('Worker is not associated to Task!');
}).to.throw(Error, 'Worker is not associated to Task!')
done() done()
}) })
})
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
this.Worker.find({ this.Worker.find({
...@@ -577,11 +577,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -577,11 +577,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
describe('hasOne with alias', function() { describe('hasOne with alias', function() {
it('throws an error if included DaoFactory is not referenced by alias', function(done) { it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this var self = this
expect(function() { self.Worker.find({ include: [ self.Task ] }).catch(function(err) {
self.Worker.find({ include: [ self.Task ] }) expect(err.message).to.equal('Task is not associated to Worker!');
}).to.throw(Error, 'Task is not associated to Worker!')
done() done()
}) })
})
describe('alias', function() { describe('alias', function() {
beforeEach(function(done) { beforeEach(function(done) {
...@@ -596,11 +596,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -596,11 +596,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error if alias is not associated', function(done) { it('throws an error if alias is not associated', function(done) {
var self = this var self = this
expect(function() { self.Worker.find({ include: [ { daoFactory: self.Task, as: 'Work' } ] }).catch(function(err) {
self.Worker.find({ include: [ { daoFactory: self.Task, as: 'Work' } ] }) expect(err.message).to.equal('Task (Work) is not associated to Worker!');
}).to.throw(Error, 'Task (Work) is not associated to Worker!')
done() done()
}) })
})
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
this.Worker.find({ this.Worker.find({
...@@ -657,11 +657,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -657,11 +657,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error if included DaoFactory is not associated', function(done) { it('throws an error if included DaoFactory is not associated', function(done) {
var self = this var self = this
expect(function() { self.Task.find({ include: [ self.Worker ] }).catch(function(err) {
self.Task.find({ include: [ self.Worker ] }) expect(err.message).to.equal('Worker is not associated to Task!');
}).to.throw(Error, 'Worker is not associated to Task!')
done() done()
}) })
})
it('returns the associated tasks via worker.tasks', function(done) { it('returns the associated tasks via worker.tasks', function(done) {
this.Worker.find({ this.Worker.find({
...@@ -759,11 +759,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -759,11 +759,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
describe('hasMany with alias', function() { describe('hasMany with alias', function() {
it('throws an error if included DaoFactory is not referenced by alias', function(done) { it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this var self = this
expect(function() { self.Worker.find({ include: [ self.Task ] }).catch(function(err) {
self.Worker.find({ include: [ self.Task ] }) expect(err.message).to.equal('Task is not associated to Worker!');
}).to.throw(Error, 'Task is not associated to Worker!')
done() done()
}) })
})
describe('alias', function() { describe('alias', function() {
beforeEach(function(done) { beforeEach(function(done) {
...@@ -778,11 +778,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -778,11 +778,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error if alias is not associated', function(done) { it('throws an error if alias is not associated', function(done) {
var self = this var self = this
expect(function() { self.Worker.find({ include: [ { daoFactory: self.Task, as: 'Work' } ] }).catch(function(err) {
self.Worker.find({ include: [ { daoFactory: self.Task, as: 'Work' } ] }) expect(err.message).to.equal('Task (Work) is not associated to Worker!');
}).to.throw(Error, 'Task (Work) is not associated to Worker!')
done() done()
}) })
})
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
this.Worker.find({ this.Worker.find({
......
...@@ -575,19 +575,19 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -575,19 +575,19 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error about unexpected input if include contains a non-object', function(done) { it('throws an error about unexpected input if include contains a non-object', function(done) {
var self = this var self = this
expect(function() { self.Worker.all({ include: [ 1 ] }).catch(function(err) {
self.Worker.all({ include: [ 1 ] }) expect(err.message).to.equal('Include unexpected. Element has to be either a Model, an Association or an object.');
}).to.throw(Error)
done() done()
}) })
})
it('throws an error if included DaoFactory is not associated', function(done) { it('throws an error if included DaoFactory is not associated', function(done) {
var self = this var self = this
expect(function() { self.Worker.all({ include: [ self.Task ] }).catch(function(err) {
self.Worker.all({ include: [ self.Task ] }) expect(err.message).to.equal('TaskBelongsTo is not associated to Worker!');
}).to.throw(Error, 'TaskBelongsTo is not associated to Worker!')
done() done()
}) })
})
it('returns the associated worker via task.worker', function(done) { it('returns the associated worker via task.worker', function(done) {
this.Task.all({ this.Task.all({
...@@ -627,11 +627,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -627,11 +627,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error if included DaoFactory is not associated', function(done) { it('throws an error if included DaoFactory is not associated', function(done) {
var self = this var self = this
expect(function() { self.Task.all({ include: [ self.Worker ] }).catch(function(err) {
self.Task.all({ include: [ self.Worker ] }) expect(err.message).to.equal('Worker is not associated to TaskHasOne!');
}).to.throw(Error, 'Worker is not associated to TaskHasOne!')
done() done()
}) })
})
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
this.Worker.all({ this.Worker.all({
...@@ -672,19 +672,19 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -672,19 +672,19 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error if included DaoFactory is not referenced by alias', function(done) { it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this var self = this
expect(function() { self.Worker.all({ include: [ self.Task ] }).catch(function(err) {
self.Worker.all({ include: [ self.Task ] }) expect(err.message).to.equal('Task is not associated to Worker!');
}).to.throw(Error, 'Task is not associated to Worker!')
done() done()
}) })
})
it('throws an error if alias is not associated', function(done) { it('throws an error if alias is not associated', function(done) {
var self = this var self = this
expect(function() { self.Worker.all({ include: [ { daoFactory: self.Task, as: 'Work' } ] }).catch(function(err) {
self.Worker.all({ include: [ { daoFactory: self.Task, as: 'Work' } ] }) expect(err.message).to.equal('Task (Work) is not associated to Worker!');
}).to.throw(Error, 'Task (Work) is not associated to Worker!')
done() done()
}) })
})
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
this.Worker.all({ this.Worker.all({
...@@ -735,11 +735,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -735,11 +735,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error if included DaoFactory is not associated', function(done) { it('throws an error if included DaoFactory is not associated', function(done) {
var self = this var self = this
expect(function() { self.Task.findAll({ include: [ self.Worker ] }).catch(function(err) {
self.Task.findAll({ include: [ self.Worker ] }) expect(err.message).to.equal('worker is not associated to task!');
}).to.throw(Error, 'worker is not associated to task!')
done() done()
}) })
})
it('returns the associated tasks via worker.tasks', function(done) { it('returns the associated tasks via worker.tasks', function(done) {
this.Worker.findAll({ this.Worker.findAll({
...@@ -780,19 +780,19 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -780,19 +780,19 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
it('throws an error if included DaoFactory is not referenced by alias', function(done) { it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this var self = this
expect(function() { self.Worker.findAll({ include: [ self.Task ] }).catch(function(err) {
self.Worker.findAll({ include: [ self.Task ] }) expect(err.message).to.equal('Task is not associated to Worker!');
}).to.throw(Error, 'Task is not associated to Worker!')
done() done()
}) })
})
it('throws an error if alias is not associated', function(done) { it('throws an error if alias is not associated', function(done) {
var self = this var self = this
expect(function() { self.Worker.findAll({ include: [ { daoFactory: self.Task, as: 'Work' } ] }).catch(function(err) {
self.Worker.findAll({ include: [ { daoFactory: self.Task, as: 'Work' } ] }) expect(err.message).to.equal('Task (Work) is not associated to Worker!');
}).to.throw(Error, 'Task (Work) is not associated to Worker!')
done() done()
}) })
})
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
this.Worker.findAll({ this.Worker.findAll({
......
This diff could not be displayed because it is too large.
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!