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

Commit 3ff27d10 by Felix Becker Committed by Jan Aagaard Meier

ES6 refactor: associations (#6050)

* Make BelongsTo association an ES6 class

* ES6 refactor of belongs-to.js

* Make BelongsToMany an ES6 class

* ES6 refactor of BelongsToMany

* Make HasMany an ES6 class

* ES6 refactor of HasMany

* Make HasOne an ES6 class

* ES6 refactor of HasOne

* ES6 refactor of association helpers

* ES6 refactor of associations/index.js

* ES6 refactor of association mixin
1 parent 5d7b26c2
'use strict'; 'use strict';
var Utils = require('./../utils') const Utils = require('./../utils');
, Helpers = require('./helpers') const Helpers = require('./helpers');
, _ = require('lodash') const _ = require('lodash');
, Association = require('./base') const Association = require('./base');
, BelongsTo = require('./belongs-to') const BelongsTo = require('./belongs-to');
, HasMany = require('./has-many') const HasMany = require('./has-many');
, HasOne = require('./has-one') const HasOne = require('./has-one');
, util = require('util');
/** /**
* Many-to-many association with a join table. * Many-to-many association with a join table.
...@@ -37,8 +36,9 @@ var Utils = require('./../utils') ...@@ -37,8 +36,9 @@ var Utils = require('./../utils')
* *
* @mixin BelongsToMany * @mixin BelongsToMany
*/ */
var BelongsToMany = function(source, target, options) { class BelongsToMany extends Association {
Association.call(this); constructor(source, target, options) {
super();
options = options || {}; options = options || {};
...@@ -145,7 +145,7 @@ var BelongsToMany = function(source, target, options) { ...@@ -145,7 +145,7 @@ var BelongsToMany = function(source, target, options) {
/* /*
* Find paired association (if exists) * Find paired association (if exists)
*/ */
_.each(this.target.associations, function(association) { _.each(this.target.associations, association => {
if (association.associationType !== 'BelongsToMany') return; if (association.associationType !== 'BelongsToMany') return;
if (association.target !== this.source) return; if (association.target !== this.source) return;
...@@ -153,7 +153,7 @@ var BelongsToMany = function(source, target, options) { ...@@ -153,7 +153,7 @@ var BelongsToMany = function(source, target, options) {
this.paired = association; this.paired = association;
association.paired = this; association.paired = this;
} }
}.bind(this)); });
if (typeof this.through.model === 'string') { if (typeof this.through.model === 'string') {
if (!this.sequelize.isDefined(this.through.model)) { if (!this.sequelize.isDefined(this.through.model)) {
...@@ -192,8 +192,8 @@ var BelongsToMany = function(source, target, options) { ...@@ -192,8 +192,8 @@ var BelongsToMany = function(source, target, options) {
this.associationAccessor = this.as; this.associationAccessor = this.as;
// Get singular and plural names, trying to uppercase the first letter, unless the model forbids it // Get singular and plural names, trying to uppercase the first letter, unless the model forbids it
var plural = Utils.uppercaseFirst(this.options.name.plural) const plural = Utils.uppercaseFirst(this.options.name.plural);
, singular = Utils.uppercaseFirst(this.options.name.singular); const singular = Utils.uppercaseFirst(this.options.name.singular);
this.accessors = { this.accessors = {
/** /**
...@@ -294,47 +294,44 @@ var BelongsToMany = function(source, target, options) { ...@@ -294,47 +294,44 @@ var BelongsToMany = function(source, target, options) {
*/ */
count: 'count' + plural count: 'count' + plural
}; };
}; }
util.inherits(BelongsToMany, Association);
// the id is in the target table // the id is in the target table
// or in an extra table which connects two tables // or in an extra table which connects two tables
BelongsToMany.prototype.injectAttributes = function() { injectAttributes() {
var self = this;
this.identifier = this.foreignKey; this.identifier = this.foreignKey;
this.foreignIdentifier = this.otherKey; this.foreignIdentifier = this.otherKey;
// remove any PKs previously defined by sequelize // remove any PKs previously defined by sequelize
// but ignore any keys that are part of this association (#5865) // but ignore any keys that are part of this association (#5865)
_.each(this.through.model.rawAttributes, function(attribute, attributeName) { _.each(this.through.model.rawAttributes, (attribute, attributeName) => {
if (attribute.primaryKey === true && attribute._autoGenerated === true) { if (attribute.primaryKey === true && attribute._autoGenerated === true) {
if (attributeName === self.foreignKey || attributeName === self.otherKey) { if (attributeName === this.foreignKey || attributeName === this.otherKey) {
// this key is still needed as it's part of the association // this key is still needed as it's part of the association
// so just set primaryKey to false // so just set primaryKey to false
attribute.primaryKey = false; attribute.primaryKey = false;
} }
else { else {
delete self.through.model.rawAttributes[attributeName]; delete this.through.model.rawAttributes[attributeName];
} }
self.primaryKeyDeleted = true; this.primaryKeyDeleted = true;
} }
}); });
var sourceKey = this.source.rawAttributes[this.source.primaryKeyAttribute] const sourceKey = this.source.rawAttributes[this.source.primaryKeyAttribute];
, sourceKeyType = sourceKey.type const sourceKeyType = sourceKey.type;
, sourceKeyField = sourceKey.field || this.source.primaryKeyAttribute const sourceKeyField = sourceKey.field || this.source.primaryKeyAttribute;
, targetKey = this.target.rawAttributes[this.target.primaryKeyAttribute] const targetKey = this.target.rawAttributes[this.target.primaryKeyAttribute];
, targetKeyType = targetKey.type const targetKeyType = targetKey.type;
, targetKeyField = targetKey.field || this.target.primaryKeyAttribute const targetKeyField = targetKey.field || this.target.primaryKeyAttribute;
, sourceAttribute = _.defaults({}, this.foreignKeyAttribute, { type: sourceKeyType }) const sourceAttribute = _.defaults({}, this.foreignKeyAttribute, { type: sourceKeyType });
, targetAttribute = _.defaults({}, this.otherKeyAttribute, { type: targetKeyType }); const targetAttribute = _.defaults({}, this.otherKeyAttribute, { type: targetKeyType });
if (this.primaryKeyDeleted === true) { if (this.primaryKeyDeleted === true) {
targetAttribute.primaryKey = sourceAttribute.primaryKey = true; targetAttribute.primaryKey = sourceAttribute.primaryKey = true;
} else if (this.through.unique !== false) { } else if (this.through.unique !== false) {
var uniqueKey = [this.through.model.tableName, this.foreignKey, this.otherKey, 'unique'].join('_'); const uniqueKey = [this.through.model.tableName, this.foreignKey, this.otherKey, 'unique'].join('_');
targetAttribute.unique = sourceAttribute.unique = uniqueKey; targetAttribute.unique = sourceAttribute.unique = uniqueKey;
} }
...@@ -422,18 +419,17 @@ BelongsToMany.prototype.injectAttributes = function() { ...@@ -422,18 +419,17 @@ BelongsToMany.prototype.injectAttributes = function() {
Helpers.checkNamingCollision(this); Helpers.checkNamingCollision(this);
return this; return this;
}; }
BelongsToMany.prototype.injectGetter = function(obj) { injectGetter(obj) {
var association = this; const association = this;
obj[this.accessors.get] = function(options) { obj[this.accessors.get] = function(options) {
options = Utils.cloneDeep(options) || {}; options = Utils.cloneDeep(options) || {};
var instance = this const through = association.through;
, through = association.through let scopeWhere;
, scopeWhere let throughWhere;
, throughWhere;
if (association.scope) { if (association.scope) {
scopeWhere = _.clone(association.scope); scopeWhere = _.clone(association.scope);
...@@ -448,7 +444,7 @@ BelongsToMany.prototype.injectGetter = function(obj) { ...@@ -448,7 +444,7 @@ BelongsToMany.prototype.injectGetter = function(obj) {
if (Object(through.model) === through.model) { if (Object(through.model) === through.model) {
throughWhere = {}; throughWhere = {};
throughWhere[association.foreignKey] = instance.get(association.source.primaryKeyAttribute); throughWhere[association.foreignKey] = this.get(association.source.primaryKeyAttribute);
if (through.scope) { if (through.scope) {
_.assign(throughWhere, through.scope); _.assign(throughWhere, through.scope);
...@@ -470,7 +466,7 @@ BelongsToMany.prototype.injectGetter = function(obj) { ...@@ -470,7 +466,7 @@ BelongsToMany.prototype.injectGetter = function(obj) {
}); });
} }
var model = association.target; let model = association.target;
if (options.hasOwnProperty('scope')) { if (options.hasOwnProperty('scope')) {
if (!options.scope) { if (!options.scope) {
model = model.unscoped(); model = model.unscoped();
...@@ -487,8 +483,8 @@ BelongsToMany.prototype.injectGetter = function(obj) { ...@@ -487,8 +483,8 @@ BelongsToMany.prototype.injectGetter = function(obj) {
}; };
obj[this.accessors.count] = function(options) { obj[this.accessors.count] = function(options) {
var model = association.target const model = association.target;
, sequelize = model.sequelize; const sequelize = model.sequelize;
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
options.attributes = [ options.attributes = [
...@@ -498,13 +494,11 @@ BelongsToMany.prototype.injectGetter = function(obj) { ...@@ -498,13 +494,11 @@ BelongsToMany.prototype.injectGetter = function(obj) {
options.raw = true; options.raw = true;
options.plain = true; options.plain = true;
return obj[association.accessors.get].call(this, options).then(function (result) { return obj[association.accessors.get].call(this, options).then(result => parseInt(result.count, 10));
return parseInt(result.count, 10);
});
}; };
obj[this.accessors.hasSingle] = obj[this.accessors.hasAll] = function(instances, options) { obj[this.accessors.hasSingle] = obj[this.accessors.hasAll] = function(instances, options) {
var where = {}; const where = {};
if (!Array.isArray(instances)) { if (!Array.isArray(instances)) {
instances = [instances]; instances = [instances];
...@@ -516,11 +510,11 @@ BelongsToMany.prototype.injectGetter = function(obj) { ...@@ -516,11 +510,11 @@ BelongsToMany.prototype.injectGetter = function(obj) {
scope: false scope: false
}); });
where.$or = instances.map(function (instance) { where.$or = instances.map(instance => {
if (instance instanceof association.target) { if (instance instanceof association.target) {
return instance.where(); return instance.where();
} else { } else {
var $where = {}; const $where = {};
$where[association.target.primaryKeyAttribute] = instance; $where[association.target.primaryKeyAttribute] = instance;
return $where; return $where;
} }
...@@ -533,25 +527,22 @@ BelongsToMany.prototype.injectGetter = function(obj) { ...@@ -533,25 +527,22 @@ BelongsToMany.prototype.injectGetter = function(obj) {
] ]
}; };
return this[association.accessors.get](options).then(function(associatedObjects) { return this[association.accessors.get](options).then(associatedObjects => associatedObjects.length === instances.length);
return associatedObjects.length === instances.length;
});
}; };
return this; return this;
}; }
BelongsToMany.prototype.injectSetter = function(obj) { injectSetter(obj) {
var association = this; const association = this;
obj[this.accessors.set] = function(newAssociatedObjects, options) { obj[this.accessors.set] = function(newAssociatedObjects, options) {
options = options || {}; options = options || {};
var instance = this const sourceKey = association.source.primaryKeyAttribute;
, sourceKey = association.source.primaryKeyAttribute const targetKey = association.target.primaryKeyAttribute;
, targetKey = association.target.primaryKeyAttribute const identifier = association.identifier;
, identifier = association.identifier const foreignIdentifier = association.foreignIdentifier;
, foreignIdentifier = association.foreignIdentifier const where = {};
, where = {};
if (newAssociatedObjects === null) { if (newAssociatedObjects === null) {
newAssociatedObjects = []; newAssociatedObjects = [];
...@@ -560,69 +551,55 @@ BelongsToMany.prototype.injectSetter = function(obj) { ...@@ -560,69 +551,55 @@ BelongsToMany.prototype.injectSetter = function(obj) {
} }
where[identifier] = this.get(sourceKey); where[identifier] = this.get(sourceKey);
return association.through.model.findAll(_.defaults({ return association.through.model.findAll(_.defaults({where, raw: true}, options)).then(currentRows => {
where: where, const obsoleteAssociations = [];
raw: true, const promises = [];
}, options)).then(function (currentRows) { let defaultAttributes = options;
var obsoleteAssociations = []
, defaultAttributes = options
, promises = []
, unassociatedObjects;
// Don't try to insert the transaction as an attribute in the through table // Don't try to insert the transaction as an attribute in the through table
defaultAttributes = _.omit(defaultAttributes, ['transaction', 'hooks', 'individualHooks', 'ignoreDuplicates', 'validate', 'fields', 'logging']); defaultAttributes = _.omit(defaultAttributes, ['transaction', 'hooks', 'individualHooks', 'ignoreDuplicates', 'validate', 'fields', 'logging']);
unassociatedObjects = newAssociatedObjects.filter(function(obj) { const unassociatedObjects = newAssociatedObjects.filter(obj =>
return !_.find(currentRows, function(currentRow) { !_.find(currentRows, currentRow => currentRow[foreignIdentifier] === obj.get(targetKey))
return currentRow[foreignIdentifier] === obj.get(targetKey); );
});
});
currentRows.forEach(function(currentRow) { for (const currentRow of currentRows) {
var newObj = _.find(newAssociatedObjects, function(obj) { const newObj = _.find(newAssociatedObjects, obj => currentRow[foreignIdentifier] === obj.get(targetKey));
return currentRow[foreignIdentifier] === obj.get(targetKey);
});
if (!newObj) { if (!newObj) {
obsoleteAssociations.push(currentRow); obsoleteAssociations.push(currentRow);
} else { } else {
var throughAttributes = newObj[association.through.model.name]; let throughAttributes = newObj[association.through.model.name];
// Quick-fix for subtle bug when using existing objects that might have the through model attached (not as an attribute object) // Quick-fix for subtle bug when using existing objects that might have the through model attached (not as an attribute object)
if (throughAttributes instanceof association.through.model) { if (throughAttributes instanceof association.through.model) {
throughAttributes = {}; throughAttributes = {};
} }
var where = {} const where = {};
, attributes = _.defaults({}, throughAttributes, defaultAttributes); const attributes = _.defaults({}, throughAttributes, defaultAttributes);
where[identifier] = instance.get(sourceKey); where[identifier] = this.get(sourceKey);
where[foreignIdentifier] = newObj.get(targetKey); where[foreignIdentifier] = newObj.get(targetKey);
if (Object.keys(attributes).length) { if (Object.keys(attributes).length) {
promises.push(association.through.model.update(attributes, _.extend(options, { promises.push(association.through.model.update(attributes, _.extend(options, {where})));
where: where }
})));
} }
} }
});
if (obsoleteAssociations.length > 0) { if (obsoleteAssociations.length > 0) {
var where = {}; const where = {};
where[identifier] = instance.get(sourceKey); where[identifier] = this.get(sourceKey);
where[foreignIdentifier] = obsoleteAssociations.map(function(obsoleteAssociation) { where[foreignIdentifier] = obsoleteAssociations.map(obsoleteAssociation => obsoleteAssociation[foreignIdentifier]);
return obsoleteAssociation[foreignIdentifier];
});
promises.push(association.through.model.destroy(_.defaults({ promises.push(association.through.model.destroy(_.defaults({where}, options)));
where: where
}, options)));
} }
if (unassociatedObjects.length > 0) { if (unassociatedObjects.length > 0) {
var bulk = unassociatedObjects.map(function(unassociatedObject) { const bulk = unassociatedObjects.map(unassociatedObject => {
var attributes = {}; let attributes = {};
attributes[identifier] = instance.get(sourceKey); attributes[identifier] = this.get(sourceKey);
attributes[foreignIdentifier] = unassociatedObject.get(targetKey); attributes[foreignIdentifier] = unassociatedObject.get(targetKey);
attributes = _.defaults(attributes, unassociatedObject[association.through.model.name], defaultAttributes); attributes = _.defaults(attributes, unassociatedObject[association.through.model.name], defaultAttributes);
...@@ -630,7 +607,7 @@ BelongsToMany.prototype.injectSetter = function(obj) { ...@@ -630,7 +607,7 @@ BelongsToMany.prototype.injectSetter = function(obj) {
_.assign(attributes, association.through.scope); _.assign(attributes, association.through.scope);
return attributes; return attributes;
}.bind(this)); });
promises.push(association.through.model.bulkCreate(bulk, _.assign({ validate: true }, options))); promises.push(association.through.model.bulkCreate(bulk, _.assign({ validate: true }, options)));
} }
...@@ -645,80 +622,70 @@ BelongsToMany.prototype.injectSetter = function(obj) { ...@@ -645,80 +622,70 @@ BelongsToMany.prototype.injectSetter = function(obj) {
additionalAttributes = _.clone(additionalAttributes) || {}; additionalAttributes = _.clone(additionalAttributes) || {};
var instance = this const defaultAttributes = _.omit(additionalAttributes, ['transaction', 'hooks', 'individualHooks', 'ignoreDuplicates', 'validate', 'fields', 'logging']);
, defaultAttributes = _.omit(additionalAttributes, ['transaction', 'hooks', 'individualHooks', 'ignoreDuplicates', 'validate', 'fields', 'logging']) const sourceKey = association.source.primaryKeyAttribute;
, sourceKey = association.source.primaryKeyAttribute const targetKey = association.target.primaryKeyAttribute;
, targetKey = association.target.primaryKeyAttribute const identifier = association.identifier;
, identifier = association.identifier const foreignIdentifier = association.foreignIdentifier;
, foreignIdentifier = association.foreignIdentifier const options = additionalAttributes;
, options = additionalAttributes;
newInstances = association.toInstanceArray(newInstances); newInstances = association.toInstanceArray(newInstances);
var where = {}; const where = {};
where[identifier] = instance.get(sourceKey); where[identifier] = this.get(sourceKey);
where[foreignIdentifier] = newInstances.map(function (newInstance) { return newInstance.get(targetKey); }); where[foreignIdentifier] = newInstances.map(newInstance => newInstance.get(targetKey));
_.assign(where, association.through.scope); _.assign(where, association.through.scope);
return association.through.model.findAll(_.defaults({ return association.through.model.findAll(_.defaults({where, raw: true}, options)).then(currentRows => {
where: where, const promises = [];
raw: true, const unassociatedObjects = [];
}, options)).then(function (currentRows) { const changedAssociations = [];
var promises = []; for (const obj of newInstances) {
const existingAssociation = _.find(currentRows, current => current[foreignIdentifier] === obj.get(targetKey));
var unassociatedObjects = [], changedAssociations = [];
newInstances.forEach(function(obj) {
var existingAssociation = _.find(currentRows, function(current) {
return current[foreignIdentifier] === obj.get(targetKey);
});
if (!existingAssociation) { if (!existingAssociation) {
unassociatedObjects.push(obj); unassociatedObjects.push(obj);
} else { } else {
var throughAttributes = obj[association.through.model.name] const throughAttributes = obj[association.through.model.name];
, attributes = _.defaults({}, throughAttributes, defaultAttributes); const attributes = _.defaults({}, throughAttributes, defaultAttributes);
if (_.some(Object.keys(attributes), function (attribute) { if (_.some(Object.keys(attributes), attribute => attributes[attribute] !== existingAssociation[attribute])) {
return attributes[attribute] !== existingAssociation[attribute];
})) {
changedAssociations.push(obj); changedAssociations.push(obj);
} }
} }
}); }
if (unassociatedObjects.length > 0) { if (unassociatedObjects.length > 0) {
var bulk = unassociatedObjects.map(function(unassociatedObject) { const bulk = unassociatedObjects.map(unassociatedObject => {
var throughAttributes = unassociatedObject[association.through.model.name] const throughAttributes = unassociatedObject[association.through.model.name];
, attributes = _.defaults({}, throughAttributes, defaultAttributes); const attributes = _.defaults({}, throughAttributes, defaultAttributes);
attributes[identifier] = instance.get(sourceKey); attributes[identifier] = this.get(sourceKey);
attributes[foreignIdentifier] = unassociatedObject.get(targetKey); attributes[foreignIdentifier] = unassociatedObject.get(targetKey);
_.assign(attributes, association.through.scope); _.assign(attributes, association.through.scope);
return attributes; return attributes;
}.bind(this)); });
promises.push(association.through.model.bulkCreate(bulk, _.assign({ validate: true }, options))); promises.push(association.through.model.bulkCreate(bulk, _.assign({ validate: true }, options)));
} }
changedAssociations.forEach(function(assoc) { for (const assoc of changedAssociations) {
var throughAttributes = assoc[association.through.model.name] let throughAttributes = assoc[association.through.model.name];
, attributes = _.defaults({}, throughAttributes, defaultAttributes) const attributes = _.defaults({}, throughAttributes, defaultAttributes);
, where = {}; const where = {};
// Quick-fix for subtle bug when using existing objects that might have the through model attached (not as an attribute object) // Quick-fix for subtle bug when using existing objects that might have the through model attached (not as an attribute object)
if (throughAttributes instanceof association.through.model) { if (throughAttributes instanceof association.through.model) {
throughAttributes = {}; throughAttributes = {};
} }
where[identifier] = instance.get(sourceKey); where[identifier] = this.get(sourceKey);
where[foreignIdentifier] = assoc.get(targetKey); where[foreignIdentifier] = assoc.get(targetKey);
promises.push(association.through.model.update(attributes, _.extend(options, { promises.push(association.through.model.update(attributes, _.extend(options, {where})));
where: where }
})));
});
return Utils.Promise.all(promises); return Utils.Promise.all(promises);
}); });
...@@ -729,23 +696,20 @@ BelongsToMany.prototype.injectSetter = function(obj) { ...@@ -729,23 +696,20 @@ BelongsToMany.prototype.injectSetter = function(obj) {
oldAssociatedObjects = association.toInstanceArray(oldAssociatedObjects); oldAssociatedObjects = association.toInstanceArray(oldAssociatedObjects);
var where = {}; const where = {};
where[association.identifier] = this.get(association.source.primaryKeyAttribute); where[association.identifier] = this.get(association.source.primaryKeyAttribute);
where[association.foreignIdentifier] = oldAssociatedObjects.map(function (newInstance) { return newInstance.get(association.target.primaryKeyAttribute); }); where[association.foreignIdentifier] = oldAssociatedObjects.map(newInstance => newInstance.get(association.target.primaryKeyAttribute));
return association.through.model.destroy(_.defaults({ return association.through.model.destroy(_.defaults({where}, options));
where: where
}, options));
}; };
return this; return this;
}; }
BelongsToMany.prototype.injectCreator = function(obj) { injectCreator(obj) {
var association = this; const association = this;
obj[this.accessors.create] = function(values, options) { obj[this.accessors.create] = function(values, options) {
var instance = this;
options = options || {}; options = options || {};
values = values || {}; values = values || {};
...@@ -763,12 +727,15 @@ BelongsToMany.prototype.injectCreator = function(obj) { ...@@ -763,12 +727,15 @@ BelongsToMany.prototype.injectCreator = function(obj) {
} }
// Create the related model instance // Create the related model instance
return association.target.create(values, options).then(function(newAssociatedObject) { return association.target.create(values, options).then(newAssociatedObject =>
return instance[association.accessors.add](newAssociatedObject, _.omit(options, ['fields'])).return(newAssociatedObject); this[association.accessors.add](newAssociatedObject, _.omit(options, ['fields'])).return(newAssociatedObject)
}); );
}; };
return this; return this;
}; }
}
module.exports = BelongsToMany; module.exports = BelongsToMany;
module.exports.BelongsToMany = BelongsToMany;
module.exports.default = BelongsToMany;
'use strict'; 'use strict';
var Utils = require('./../utils') const Utils = require('./../utils');
, Helpers = require('./helpers') const Helpers = require('./helpers');
, _ = require('lodash') const _ = require('lodash');
, Transaction = require('../transaction') const Transaction = require('../transaction');
, Association = require('./base') const Association = require('./base');
, util = require('util');
/** /**
* One-to-one association * One-to-one association
...@@ -14,8 +13,9 @@ var Utils = require('./../utils') ...@@ -14,8 +13,9 @@ var Utils = require('./../utils')
* *
* @mixin BelongsTo * @mixin BelongsTo
*/ */
var BelongsTo = function(source, target, options) { class BelongsTo extends Association {
Association.call(this); constructor(source, target, options) {
super();
this.associationType = 'BelongsTo'; this.associationType = 'BelongsTo';
this.source = source; this.source = source;
...@@ -69,7 +69,7 @@ var BelongsTo = function(source, target, options) { ...@@ -69,7 +69,7 @@ var BelongsTo = function(source, target, options) {
this.options.useHooks = options.useHooks; this.options.useHooks = options.useHooks;
// Get singular name, trying to uppercase the first letter, unless the model forbids it // Get singular name, trying to uppercase the first letter, unless the model forbids it
var singular = Utils.uppercaseFirst(this.options.name.singular); const singular = Utils.uppercaseFirst(this.options.name.singular);
this.accessors = { this.accessors = {
/** /**
...@@ -104,13 +104,11 @@ var BelongsTo = function(source, target, options) { ...@@ -104,13 +104,11 @@ var BelongsTo = function(source, target, options) {
*/ */
create: 'create' + singular create: 'create' + singular
}; };
}; }
util.inherits(BelongsTo, Association);
// the id is in the source table // the id is in the source table
BelongsTo.prototype.injectAttributes = function() { injectAttributes() {
var newAttributes = {}; const newAttributes = {};
newAttributes[this.foreignKey] = _.defaults({}, this.foreignKeyAttribute, { newAttributes[this.foreignKey] = _.defaults({}, this.foreignKeyAttribute, {
type: this.options.keyType || this.target.rawAttributes[this.targetKey].type, type: this.options.keyType || this.target.rawAttributes[this.targetKey].type,
...@@ -118,7 +116,7 @@ BelongsTo.prototype.injectAttributes = function() { ...@@ -118,7 +116,7 @@ BelongsTo.prototype.injectAttributes = function() {
}); });
if (this.options.constraints !== false) { if (this.options.constraints !== false) {
var source = this.source.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey]; const source = this.source.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey];
this.options.onDelete = this.options.onDelete || (source.allowNull ? 'SET NULL' : 'NO ACTION'); this.options.onDelete = this.options.onDelete || (source.allowNull ? 'SET NULL' : 'NO ACTION');
this.options.onUpdate = this.options.onUpdate || 'CASCADE'; this.options.onUpdate = this.options.onUpdate || 'CASCADE';
} }
...@@ -133,10 +131,10 @@ BelongsTo.prototype.injectAttributes = function() { ...@@ -133,10 +131,10 @@ BelongsTo.prototype.injectAttributes = function() {
Helpers.checkNamingCollision(this); Helpers.checkNamingCollision(this);
return this; return this;
}; }
BelongsTo.prototype.mixin = function(obj) { mixin(obj) {
var association = this; const association = this;
obj[this.accessors.get] = function(options) { obj[this.accessors.get] = function(options) {
return association.get(this, options); return association.get(this, options);
...@@ -144,13 +142,13 @@ BelongsTo.prototype.mixin = function(obj) { ...@@ -144,13 +142,13 @@ BelongsTo.prototype.mixin = function(obj) {
association.injectSetter(obj); association.injectSetter(obj);
association.injectCreator(obj); association.injectCreator(obj);
}; }
BelongsTo.prototype.get = function(instances, options) { get(instances, options) {
var association = this const association = this;
, Target = association.target const where = {};
, instance let Target = association.target;
, where = {}; let instance;
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
...@@ -173,9 +171,7 @@ BelongsTo.prototype.get = function(instances, options) { ...@@ -173,9 +171,7 @@ BelongsTo.prototype.get = function(instances, options) {
if (instances) { if (instances) {
where[association.targetKey] = { where[association.targetKey] = {
$in: instances.map(function (instance) { $in: instances.map(instance => instance.get(association.foreignKey))
return instance.get(association.foreignKey);
})
}; };
} else { } else {
if (association.targetKeyIsPrimary && !options.where) { if (association.targetKeyIsPrimary && !options.where) {
...@@ -191,30 +187,30 @@ BelongsTo.prototype.get = function(instances, options) { ...@@ -191,30 +187,30 @@ BelongsTo.prototype.get = function(instances, options) {
where; where;
if (instances) { if (instances) {
return Target.findAll(options).then(function (results) { return Target.findAll(options).then(results => {
var result = {}; const result = {};
instances.forEach(function (instance) { for (const instance of instances) {
result[instance.get(association.foreignKey, {raw: true})] = null; result[instance.get(association.foreignKey, {raw: true})] = null;
}); }
results.forEach(function (instance) { for (const instance of results) {
result[instance.get(association.targetKey, {raw: true})] = instance; result[instance.get(association.targetKey, {raw: true})] = instance;
}); }
return result; return result;
}); });
} }
return Target.findOne(options); return Target.findOne(options);
}; }
// Add setAssociaton method to the prototype of the model instance // Add setAssociaton method to the prototype of the model instance
BelongsTo.prototype.injectSetter = function(instancePrototype) { injectSetter(instancePrototype) {
var association = this; const association = this;
instancePrototype[this.accessors.set] = function(associatedInstance, options) { instancePrototype[this.accessors.set] = function(associatedInstance, options) {
options = options || {}; options = options || {};
var value = associatedInstance; let value = associatedInstance;
if (associatedInstance instanceof association.target) { if (associatedInstance instanceof association.target) {
value = associatedInstance[association.targetKey]; value = associatedInstance[association.targetKey];
} }
...@@ -235,27 +231,29 @@ BelongsTo.prototype.injectSetter = function(instancePrototype) { ...@@ -235,27 +231,29 @@ BelongsTo.prototype.injectSetter = function(instancePrototype) {
}; };
return this; return this;
}; }
// Add createAssociation method to the prototype of the model instance // Add createAssociation method to the prototype of the model instance
BelongsTo.prototype.injectCreator = function(instancePrototype) { injectCreator(instancePrototype) {
var association = this; const association = this;
instancePrototype[this.accessors.create] = function(values, fieldsOrOptions) { instancePrototype[this.accessors.create] = function(values, fieldsOrOptions) {
var instance = this const options = {};
, options = {};
if ((fieldsOrOptions || {}).transaction instanceof Transaction) { if ((fieldsOrOptions || {}).transaction instanceof Transaction) {
options.transaction = fieldsOrOptions.transaction; options.transaction = fieldsOrOptions.transaction;
} }
options.logging = (fieldsOrOptions || {}).logging; options.logging = (fieldsOrOptions || {}).logging;
return association.target.create(values, fieldsOrOptions).then(function(newAssociatedObject) { return association.target.create(values, fieldsOrOptions).then(newAssociatedObject =>
return instance[association.accessors.set](newAssociatedObject, options); this[association.accessors.set](newAssociatedObject, options)
}); );
}; };
return this; return this;
}; }
}
module.exports = BelongsTo; module.exports = BelongsTo;
module.exports.BelongsTo = BelongsTo;
module.exports.default = BelongsTo;
'use strict'; 'use strict';
var Utils = require('./../utils') const Utils = require('./../utils');
, Helpers = require('./helpers') const Helpers = require('./helpers');
, _ = require('lodash') const _ = require('lodash');
, Association = require('./base') const Association = require('./base');
, util = require('util');
/** /**
* One-to-many association * One-to-many association
...@@ -13,8 +12,9 @@ var Utils = require('./../utils') ...@@ -13,8 +12,9 @@ var Utils = require('./../utils')
* *
* @mixin HasMany * @mixin HasMany
*/ */
var HasMany = function(source, target, options) { class HasMany extends Association {
Association.call(this); constructor(source, target, options) {
super();
this.associationType = 'HasMany'; this.associationType = 'HasMany';
this.source = source; this.source = source;
...@@ -86,8 +86,8 @@ var HasMany = function(source, target, options) { ...@@ -86,8 +86,8 @@ var HasMany = function(source, target, options) {
this.associationAccessor = this.as; this.associationAccessor = this.as;
// Get singular and plural names, trying to uppercase the first letter, unless the model forbids it // Get singular and plural names, trying to uppercase the first letter, unless the model forbids it
var plural = Utils.uppercaseFirst(this.options.name.plural) const plural = Utils.uppercaseFirst(this.options.name.plural);
, singular = Utils.uppercaseFirst(this.options.name.singular); const singular = Utils.uppercaseFirst(this.options.name.singular);
this.accessors = { this.accessors = {
/** /**
...@@ -188,22 +188,20 @@ var HasMany = function(source, target, options) { ...@@ -188,22 +188,20 @@ var HasMany = function(source, target, options) {
*/ */
count: 'count' + plural count: 'count' + plural
}; };
}; }
util.inherits(HasMany, Association);
// the id is in the target table // the id is in the target table
// or in an extra table which connects two tables // or in an extra table which connects two tables
HasMany.prototype.injectAttributes = function() { injectAttributes() {
var newAttributes = {}; const newAttributes = {};
var constraintOptions = _.clone(this.options); // Create a new options object for use with addForeignKeyConstraints, to avoid polluting this.options in case it is later used for a n:m const constraintOptions = _.clone(this.options); // Create a new options object for use with addForeignKeyConstraints, to avoid polluting this.options in case it is later used for a n:m
newAttributes[this.foreignKey] = _.defaults({}, this.foreignKeyAttribute, { newAttributes[this.foreignKey] = _.defaults({}, this.foreignKeyAttribute, {
type: this.options.keyType || this.source.rawAttributes[this.source.primaryKeyAttribute].type, type: this.options.keyType || this.source.rawAttributes[this.source.primaryKeyAttribute].type,
allowNull : true allowNull : true
}); });
if (this.options.constraints !== false) { if (this.options.constraints !== false) {
var target = this.target.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey]; const target = this.target.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey];
constraintOptions.onDelete = constraintOptions.onDelete || (target.allowNull ? 'SET NULL' : 'CASCADE'); constraintOptions.onDelete = constraintOptions.onDelete || (target.allowNull ? 'SET NULL' : 'CASCADE');
constraintOptions.onUpdate = constraintOptions.onUpdate || 'CASCADE'; constraintOptions.onUpdate = constraintOptions.onUpdate || 'CASCADE';
} }
...@@ -219,10 +217,10 @@ HasMany.prototype.injectAttributes = function() { ...@@ -219,10 +217,10 @@ HasMany.prototype.injectAttributes = function() {
Helpers.checkNamingCollision(this); Helpers.checkNamingCollision(this);
return this; return this;
}; }
HasMany.prototype.mixin = function(obj) { mixin(obj) {
var association = this; const association = this;
obj[this.accessors.get] = function(options) { obj[this.accessors.get] = function(options) {
return association.get(this, options); return association.get(this, options);
...@@ -253,14 +251,14 @@ HasMany.prototype.mixin = function(obj) { ...@@ -253,14 +251,14 @@ HasMany.prototype.mixin = function(obj) {
obj[this.accessors.create] = function(values, options) { obj[this.accessors.create] = function(values, options) {
return association.create(this, values, options); return association.create(this, values, options);
}; };
}; }
HasMany.prototype.get = function(instances, options) { get(instances, options) {
var association = this const association = this;
, where = {} const where = {};
, Model = association.target let Model = association.target;
, instance let instance;
, values; let values;
if (!Array.isArray(instances)) { if (!Array.isArray(instances)) {
instance = instances; instance = instances;
...@@ -274,15 +272,13 @@ HasMany.prototype.get = function(instances, options) { ...@@ -274,15 +272,13 @@ HasMany.prototype.get = function(instances, options) {
} }
if (instances) { if (instances) {
values = instances.map(function (instance) { values = instances.map(instance => instance.get(association.source.primaryKeyAttribute, {raw: true}));
return instance.get(association.source.primaryKeyAttribute, {raw: true});
});
if (options.limit && instances.length > 1) { if (options.limit && instances.length > 1) {
options.groupedLimit = { options.groupedLimit = {
limit: options.limit, limit: options.limit,
on: association.foreignKeyField, on: association.foreignKeyField,
values: values values
}; };
delete options.limit; delete options.limit;
...@@ -314,26 +310,26 @@ HasMany.prototype.get = function(instances, options) { ...@@ -314,26 +310,26 @@ HasMany.prototype.get = function(instances, options) {
} }
return Model.findAll(options).then(function (results) { return Model.findAll(options).then(results => {
if (instance) return results; if (instance) return results;
var result = {}; const result = {};
instances.forEach(function (instance) { for (const instance of instances) {
result[instance.get(association.source.primaryKeyAttribute, {raw: true})] = []; result[instance.get(association.source.primaryKeyAttribute, {raw: true})] = [];
}); }
results.forEach(function (instance) { for (const instance of results) {
result[instance.get(association.foreignKey, {raw: true})].push(instance); result[instance.get(association.foreignKey, {raw: true})].push(instance);
}); }
return result; return result;
}); });
}; }
HasMany.prototype.count = function(instance, options) { count(instance, options) {
var association = this const association = this;
, model = association.target const model = association.target;
, sequelize = model.sequelize; const sequelize = model.sequelize;
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
options.attributes = [ options.attributes = [
...@@ -342,14 +338,12 @@ HasMany.prototype.count = function(instance, options) { ...@@ -342,14 +338,12 @@ HasMany.prototype.count = function(instance, options) {
options.raw = true; options.raw = true;
options.plain = true; options.plain = true;
return this.get(instance, options).then(function (result) { return this.get(instance, options).then(result => parseInt(result.count, 10));
return parseInt(result.count, 10); }
});
};
HasMany.prototype.has = function(sourceInstance, targetInstances, options) { has(sourceInstance, targetInstances, options) {
var association = this const association = this;
, where = {}; const where = {};
if (!Array.isArray(targetInstances)) { if (!Array.isArray(targetInstances)) {
targetInstances = [targetInstances]; targetInstances = [targetInstances];
...@@ -360,11 +354,11 @@ HasMany.prototype.has = function(sourceInstance, targetInstances, options) { ...@@ -360,11 +354,11 @@ HasMany.prototype.has = function(sourceInstance, targetInstances, options) {
raw: true raw: true
}); });
where.$or = targetInstances.map(function (instance) { where.$or = targetInstances.map(instance => {
if (instance instanceof association.target) { if (instance instanceof association.target) {
return instance.where(); return instance.where();
} else { } else {
var _where = {}; const _where = {};
_where[association.target.primaryKeyAttribute] = instance; _where[association.target.primaryKeyAttribute] = instance;
return _where; return _where;
} }
...@@ -377,16 +371,11 @@ HasMany.prototype.has = function(sourceInstance, targetInstances, options) { ...@@ -377,16 +371,11 @@ HasMany.prototype.has = function(sourceInstance, targetInstances, options) {
] ]
}; };
return this.get( return this.get(sourceInstance, options).then(associatedObjects => associatedObjects.length === targetInstances.length);
sourceInstance, }
options
).then(function(associatedObjects) {
return associatedObjects.length === targetInstances.length;
});
};
HasMany.prototype.set = function(sourceInstance, targetInstances, options) { set(sourceInstance, targetInstances, options) {
var association = this; const association = this;
if (targetInstances === null) { if (targetInstances === null) {
targetInstances = []; targetInstances = [];
...@@ -394,23 +383,20 @@ HasMany.prototype.set = function(sourceInstance, targetInstances, options) { ...@@ -394,23 +383,20 @@ HasMany.prototype.set = function(sourceInstance, targetInstances, options) {
targetInstances = association.toInstanceArray(targetInstances); targetInstances = association.toInstanceArray(targetInstances);
} }
return association.get(sourceInstance, _.defaults({ return association.get(sourceInstance, _.defaults({scope: false, raw: true}, options)).then(oldAssociations => {
scope: false, const promises = [];
raw: true const obsoleteAssociations = oldAssociations.filter(old =>
}, options)).then(function(oldAssociations) { !_.find(targetInstances, obj =>
var promises = [] obj[association.target.primaryKeyAttribute] === old[association.target.primaryKeyAttribute]
, obsoleteAssociations = oldAssociations.filter(function(old) { )
return !_.find(targetInstances, function(obj) { );
return obj[association.target.primaryKeyAttribute] === old[association.target.primaryKeyAttribute]; const unassociatedObjects = targetInstances.filter(obj =>
}); !_.find(oldAssociations, old =>
}) obj[association.target.primaryKeyAttribute] === old[association.target.primaryKeyAttribute]
, unassociatedObjects = targetInstances.filter(function(obj) { )
return !_.find(oldAssociations, function(old) { );
return obj[association.target.primaryKeyAttribute] === old[association.target.primaryKeyAttribute]; let updateWhere;
}); let update;
})
, updateWhere
, update;
if (obsoleteAssociations.length > 0) { if (obsoleteAssociations.length > 0) {
update = {}; update = {};
...@@ -418,9 +404,9 @@ HasMany.prototype.set = function(sourceInstance, targetInstances, options) { ...@@ -418,9 +404,9 @@ HasMany.prototype.set = function(sourceInstance, targetInstances, options) {
updateWhere = {}; updateWhere = {};
updateWhere[association.target.primaryKeyAttribute] = obsoleteAssociations.map(function(associatedObject) { updateWhere[association.target.primaryKeyAttribute] = obsoleteAssociations.map(associatedObject =>
return associatedObject[association.target.primaryKeyAttribute]; associatedObject[association.target.primaryKeyAttribute]
}); );
promises.push(association.target.unscoped().update( promises.push(association.target.unscoped().update(
update, update,
...@@ -437,9 +423,9 @@ HasMany.prototype.set = function(sourceInstance, targetInstances, options) { ...@@ -437,9 +423,9 @@ HasMany.prototype.set = function(sourceInstance, targetInstances, options) {
update[association.foreignKey] = sourceInstance.get(association.source.primaryKeyAttribute); update[association.foreignKey] = sourceInstance.get(association.source.primaryKeyAttribute);
_.assign(update, association.scope); _.assign(update, association.scope);
updateWhere[association.target.primaryKeyAttribute] = unassociatedObjects.map(function(unassociatedObject) { updateWhere[association.target.primaryKeyAttribute] = unassociatedObjects.map(unassociatedObject =>
return unassociatedObject[association.target.primaryKeyAttribute]; unassociatedObject[association.target.primaryKeyAttribute]
}); );
promises.push(association.target.unscoped().update( promises.push(association.target.unscoped().update(
update, update,
...@@ -451,14 +437,14 @@ HasMany.prototype.set = function(sourceInstance, targetInstances, options) { ...@@ -451,14 +437,14 @@ HasMany.prototype.set = function(sourceInstance, targetInstances, options) {
return Utils.Promise.all(promises).return(sourceInstance); return Utils.Promise.all(promises).return(sourceInstance);
}); });
}; }
HasMany.prototype.add = function(sourceInstance, targetInstances, options) { add(sourceInstance, targetInstances, options) {
if (!targetInstances) return Utils.Promise.resolve(); if (!targetInstances) return Utils.Promise.resolve();
var association = this const association = this;
, update = {} const update = {};
, where = {}; const where = {};
options = options || {}; options = options || {};
...@@ -467,22 +453,17 @@ HasMany.prototype.add = function(sourceInstance, targetInstances, options) { ...@@ -467,22 +453,17 @@ HasMany.prototype.add = function(sourceInstance, targetInstances, options) {
update[association.foreignKey] = sourceInstance.get(association.source.primaryKeyAttribute); update[association.foreignKey] = sourceInstance.get(association.source.primaryKeyAttribute);
_.assign(update, association.scope); _.assign(update, association.scope);
where[association.target.primaryKeyAttribute] = targetInstances.map(function (unassociatedObject) { where[association.target.primaryKeyAttribute] = targetInstances.map(unassociatedObject =>
return unassociatedObject.get(association.target.primaryKeyAttribute); unassociatedObject.get(association.target.primaryKeyAttribute)
}); );
return association.target.unscoped().update( return association.target.unscoped().update(update, _.defaults({where}, options)).return(sourceInstance);
update, }
_.defaults({
where: where
}, options)
).return(sourceInstance);
};
HasMany.prototype.remove = function(sourceInstance, targetInstances, options) { remove(sourceInstance, targetInstances, options) {
var association = this const association = this;
, update = {} const update = {};
, where = {}; const where = {};
options = options || {}; options = options || {};
targetInstances = association.toInstanceArray(targetInstances); targetInstances = association.toInstanceArray(targetInstances);
...@@ -490,20 +471,15 @@ HasMany.prototype.remove = function(sourceInstance, targetInstances, options) { ...@@ -490,20 +471,15 @@ HasMany.prototype.remove = function(sourceInstance, targetInstances, options) {
update[association.foreignKey] = null; update[association.foreignKey] = null;
where[association.foreignKey] = sourceInstance.get(association.source.primaryKeyAttribute); where[association.foreignKey] = sourceInstance.get(association.source.primaryKeyAttribute);
where[association.target.primaryKeyAttribute] = targetInstances.map(function (targetInstance) { where[association.target.primaryKeyAttribute] = targetInstances.map(targetInstance =>
return targetInstance.get(association.target.primaryKeyAttribute); targetInstance.get(association.target.primaryKeyAttribute)
}); );
return association.target.unscoped().update( return association.target.unscoped().update(update, _.defaults({where}, options)).return(this);
update, }
_.defaults({
where: where
}, options)
).return(this);
};
HasMany.prototype.create = function(sourceInstance, values, options) { create(sourceInstance, values, options) {
var association = this; const association = this;
options = options || {}; options = options || {};
...@@ -518,15 +494,18 @@ HasMany.prototype.create = function(sourceInstance, values, options) { ...@@ -518,15 +494,18 @@ HasMany.prototype.create = function(sourceInstance, values, options) {
} }
if (association.scope) { if (association.scope) {
Object.keys(association.scope).forEach(function (attribute) { for (const attribute of Object.keys(association.scope)) {
values[attribute] = association.scope[attribute]; values[attribute] = association.scope[attribute];
if (options.fields) options.fields.push(attribute); if (options.fields) options.fields.push(attribute);
}); }
} }
values[association.foreignKey] = sourceInstance.get(association.source.primaryKeyAttribute); values[association.foreignKey] = sourceInstance.get(association.source.primaryKeyAttribute);
if (options.fields) options.fields.push(association.foreignKey); if (options.fields) options.fields.push(association.foreignKey);
return association.target.create(values, options); return association.target.create(values, options);
}; }
}
module.exports = HasMany; module.exports = HasMany;
module.exports.HasMany = HasMany;
module.exports.default = HasMany;
'use strict'; 'use strict';
var Utils = require('./../utils') const Utils = require('./../utils');
, Helpers = require('./helpers') const Helpers = require('./helpers');
, _ = require('lodash') const _ = require('lodash');
, Association = require('./base') const Association = require('./base');
, util = require('util');
/** /**
* One-to-one association * One-to-one association
...@@ -14,8 +13,9 @@ var Utils = require('./../utils') ...@@ -14,8 +13,9 @@ var Utils = require('./../utils')
* *
* @mixin HasOne * @mixin HasOne
*/ */
var HasOne = function(srcModel, targetModel, options) { class HasOne extends Association {
Association.call(this); constructor(srcModel, targetModel, options) {
super();
this.associationType = 'HasOne'; this.associationType = 'HasOne';
this.source = srcModel; this.source = srcModel;
...@@ -66,7 +66,7 @@ var HasOne = function(srcModel, targetModel, options) { ...@@ -66,7 +66,7 @@ var HasOne = function(srcModel, targetModel, options) {
} }
// Get singular name, trying to uppercase the first letter, unless the model forbids it // Get singular name, trying to uppercase the first letter, unless the model forbids it
var singular = Utils.uppercaseFirst(this.options.name.singular); const singular = Utils.uppercaseFirst(this.options.name.singular);
this.accessors = { this.accessors = {
/** /**
...@@ -100,14 +100,12 @@ var HasOne = function(srcModel, targetModel, options) { ...@@ -100,14 +100,12 @@ var HasOne = function(srcModel, targetModel, options) {
*/ */
create: 'create' + singular create: 'create' + singular
}; };
}; }
util.inherits(HasOne, Association);
// the id is in the target table // the id is in the target table
HasOne.prototype.injectAttributes = function() { injectAttributes() {
var newAttributes = {} const newAttributes = {};
, keyType = this.source.rawAttributes[this.source.primaryKeyAttribute].type; const keyType = this.source.rawAttributes[this.source.primaryKeyAttribute].type;
newAttributes[this.foreignKey] = _.defaults({}, this.foreignKeyAttribute, { newAttributes[this.foreignKey] = _.defaults({}, this.foreignKeyAttribute, {
type: this.options.keyType || keyType, type: this.options.keyType || keyType,
...@@ -118,7 +116,7 @@ HasOne.prototype.injectAttributes = function() { ...@@ -118,7 +116,7 @@ HasOne.prototype.injectAttributes = function() {
this.identifierField = this.target.rawAttributes[this.foreignKey].field || this.foreignKey; this.identifierField = this.target.rawAttributes[this.foreignKey].field || this.foreignKey;
if (this.options.constraints !== false) { if (this.options.constraints !== false) {
var target = this.target.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey]; const target = this.target.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey];
this.options.onDelete = this.options.onDelete || (target.allowNull ? 'SET NULL' : 'CASCADE'); this.options.onDelete = this.options.onDelete || (target.allowNull ? 'SET NULL' : 'CASCADE');
this.options.onUpdate = this.options.onUpdate || 'CASCADE'; this.options.onUpdate = this.options.onUpdate || 'CASCADE';
} }
...@@ -131,10 +129,10 @@ HasOne.prototype.injectAttributes = function() { ...@@ -131,10 +129,10 @@ HasOne.prototype.injectAttributes = function() {
Helpers.checkNamingCollision(this); Helpers.checkNamingCollision(this);
return this; return this;
}; }
HasOne.prototype.mixin = function(obj) { mixin(obj) {
var association = this; const association = this;
obj[this.accessors.get] = function(options) { obj[this.accessors.get] = function(options) {
return association.get(this, options); return association.get(this, options);
...@@ -142,13 +140,13 @@ HasOne.prototype.mixin = function(obj) { ...@@ -142,13 +140,13 @@ HasOne.prototype.mixin = function(obj) {
association.injectSetter(obj); association.injectSetter(obj);
association.injectCreator(obj); association.injectCreator(obj);
}; }
HasOne.prototype.get = function(instances, options) { get(instances, options) {
var association = this const association = this;
, Target = association.target const where = {};
, instance let Target = association.target;
, where = {}; let instance;
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
...@@ -171,9 +169,7 @@ HasOne.prototype.get = function(instances, options) { ...@@ -171,9 +169,7 @@ HasOne.prototype.get = function(instances, options) {
if (instances) { if (instances) {
where[association.foreignKey] = { where[association.foreignKey] = {
$in: instances.map(function (instance) { $in: instances.map(instance => instance.get(association.sourceKey))
return instance.get(association.sourceKey);
})
}; };
} else { } else {
where[association.foreignKey] = instance.get(association.sourceKey); where[association.foreignKey] = instance.get(association.sourceKey);
...@@ -188,37 +184,36 @@ HasOne.prototype.get = function(instances, options) { ...@@ -188,37 +184,36 @@ HasOne.prototype.get = function(instances, options) {
where; where;
if (instances) { if (instances) {
return Target.findAll(options).then(function (results) { return Target.findAll(options).then(results => {
var result = {}; const result = {};
instances.forEach(function (instance) { for (const instance of instances) {
result[instance.get(association.sourceKey, {raw: true})] = null; result[instance.get(association.sourceKey, {raw: true})] = null;
}); }
results.forEach(function (instance) { for (const instance of results) {
result[instance.get(association.foreignKey, {raw: true})] = instance; result[instance.get(association.foreignKey, {raw: true})] = instance;
}); }
return result; return result;
}); });
} }
return Target.findOne(options); return Target.findOne(options);
}; }
HasOne.prototype.injectSetter = function(instancePrototype) { injectSetter(instancePrototype) {
var association = this; const association = this;
instancePrototype[this.accessors.set] = function(associatedInstance, options) { instancePrototype[this.accessors.set] = function(associatedInstance, options) {
var instance = this, let alreadyAssociated;
alreadyAssociated;
options = _.assign({}, options, { options = _.assign({}, options, {
scope: false scope: false
}); });
return instance[association.accessors.get](options).then(function(oldInstance) { return this[association.accessors.get](options).then(oldInstance => {
// TODO Use equals method once #5605 is resolved // TODO Use equals method once #5605 is resolved
alreadyAssociated = oldInstance && associatedInstance && _.every(association.target.primaryKeyAttributes, function(attribute) { alreadyAssociated = oldInstance && associatedInstance && _.every(association.target.primaryKeyAttributes, attribute =>
return oldInstance.get(attribute, {raw: true}) === associatedInstance.get(attribute, {raw: true}); oldInstance.get(attribute, {raw: true}) === associatedInstance.get(attribute, {raw: true})
}); );
if (oldInstance && !alreadyAssociated) { if (oldInstance && !alreadyAssociated) {
oldInstance[association.foreignKey] = null; oldInstance[association.foreignKey] = null;
...@@ -228,10 +223,10 @@ HasOne.prototype.injectSetter = function(instancePrototype) { ...@@ -228,10 +223,10 @@ HasOne.prototype.injectSetter = function(instancePrototype) {
association: true association: true
})); }));
} }
}).then(function() { }).then(() => {
if (associatedInstance && !alreadyAssociated) { if (associatedInstance && !alreadyAssociated) {
if (!(associatedInstance instanceof association.target)) { if (!(associatedInstance instanceof association.target)) {
var tmpInstance = {}; const tmpInstance = {};
tmpInstance[association.target.primaryKeyAttribute] = associatedInstance; tmpInstance[association.target.primaryKeyAttribute] = associatedInstance;
associatedInstance = association.target.build(tmpInstance, { associatedInstance = association.target.build(tmpInstance, {
isNewRecord: false isNewRecord: false
...@@ -239,7 +234,7 @@ HasOne.prototype.injectSetter = function(instancePrototype) { ...@@ -239,7 +234,7 @@ HasOne.prototype.injectSetter = function(instancePrototype) {
} }
_.assign(associatedInstance, association.scope); _.assign(associatedInstance, association.scope);
associatedInstance.set(association.foreignKey, instance.get(association.sourceIdentifier)); associatedInstance.set(association.foreignKey, this.get(association.sourceIdentifier));
return associatedInstance.save(options); return associatedInstance.save(options);
} }
...@@ -248,29 +243,29 @@ HasOne.prototype.injectSetter = function(instancePrototype) { ...@@ -248,29 +243,29 @@ HasOne.prototype.injectSetter = function(instancePrototype) {
}; };
return this; return this;
}; }
HasOne.prototype.injectCreator = function(instancePrototype) { injectCreator(instancePrototype) {
var association = this; const association = this;
instancePrototype[this.accessors.create] = function(values, options) { instancePrototype[this.accessors.create] = function(values, options) {
var instance = this;
values = values || {}; values = values || {};
options = options || {}; options = options || {};
if (association.scope) { if (association.scope) {
Object.keys(association.scope).forEach(function (attribute) { for (const attribute of Object.keys(association.scope)) {
values[attribute] = association.scope[attribute]; values[attribute] = association.scope[attribute];
if (options.fields) options.fields.push(attribute); if (options.fields) options.fields.push(attribute);
}); }
} }
values[association.foreignKey] = instance.get(association.sourceIdentifier); values[association.foreignKey] = this.get(association.sourceIdentifier);
if (options.fields) options.fields.push(association.foreignKey); if (options.fields) options.fields.push(association.foreignKey);
return association.target.create(values, options); return association.target.create(values, options);
}; };
return this; return this;
}; }
}
module.exports = HasOne; module.exports = HasOne;
'use strict'; 'use strict';
var Utils = require('./../utils'); const Utils = require('./../utils');
function checkNamingCollision (association) { function checkNamingCollision (association) {
if (association.source.rawAttributes.hasOwnProperty(association.as)) { if (association.source.rawAttributes.hasOwnProperty(association.as)) {
...@@ -11,6 +11,7 @@ function checkNamingCollision (association) { ...@@ -11,6 +11,7 @@ function checkNamingCollision (association) {
); );
} }
} }
exports.checkNamingCollision = checkNamingCollision;
function addForeignKeyConstraints (newAttribute, source, target, options, key) { function addForeignKeyConstraints (newAttribute, source, target, options, key) {
// FK constraints are opt-in: users must either set `foreignKeyConstraints` // FK constraints are opt-in: users must either set `foreignKeyConstraints`
...@@ -19,9 +20,9 @@ function addForeignKeyConstraints (newAttribute, source, target, options, key) { ...@@ -19,9 +20,9 @@ function addForeignKeyConstraints (newAttribute, source, target, options, key) {
if (options.foreignKeyConstraint || options.onDelete || options.onUpdate) { if (options.foreignKeyConstraint || options.onDelete || options.onUpdate) {
// Find primary keys: composite keys not supported with this approach // Find primary keys: composite keys not supported with this approach
var primaryKeys = Utils._.chain(source.rawAttributes).keys() const primaryKeys = Utils._.chain(source.rawAttributes).keys()
.filter(function($key) { return source.rawAttributes[$key].primaryKey; }) .filter($key => source.rawAttributes[$key].primaryKey)
.map(function($key) { return source.rawAttributes[$key].field || $key; }).value(); .map($key => source.rawAttributes[$key].field || $key).value();
if (primaryKeys.length === 1) { if (primaryKeys.length === 1) {
if (!!source.$schema) { if (!!source.$schema) {
...@@ -42,8 +43,4 @@ function addForeignKeyConstraints (newAttribute, source, target, options, key) { ...@@ -42,8 +43,4 @@ function addForeignKeyConstraints (newAttribute, source, target, options, key) {
} }
} }
} }
exports.addForeignKeyConstraints = addForeignKeyConstraints;
module.exports = {
checkNamingCollision: checkNamingCollision,
addForeignKeyConstraints: addForeignKeyConstraints
};
'use strict'; 'use strict';
var Association = require('./base'); const Association = require('./base');
Association.BelongsTo = require('./belongs-to'); Association.BelongsTo = require('./belongs-to');
Association.HasOne = require('./has-one'); Association.HasOne = require('./has-one');
Association.HasMany = require('./has-many'); Association.HasMany = require('./has-many');
Association.BelongsToMany = require('./belongs-to-many'); Association.BelongsToMany = require('./belongs-to-many');
module.exports = Association; module.exports = Association;
module.exports.default = Association;
module.exports.Association = Association;
'use strict'; 'use strict';
var Utils = require('./../utils') const Utils = require('./../utils');
, _ = require('lodash') const _ = require('lodash');
, HasOne = require('./has-one') const HasOne = require('./has-one');
, HasMany = require('./has-many') const HasMany = require('./has-many');
, BelongsToMany = require('./belongs-to-many') const BelongsToMany = require('./belongs-to-many');
, BelongsTo = require('./belongs-to'); const BelongsTo = require('./belongs-to');
/** /**
* Creating associations in sequelize is done by calling one of the belongsTo / hasOne / hasMany / belongsToMany functions on a model (the source), and providing another model as the first argument to the function (the target). * Creating associations in sequelize is done by calling one of the belongsTo / hasOne / hasMany / belongsToMany functions on a model (the source), and providing another model as the first argument to the function (the target).
...@@ -86,73 +86,8 @@ var Utils = require('./../utils') ...@@ -86,73 +86,8 @@ var Utils = require('./../utils')
* @mixin Associations * @mixin Associations
* @name Associations * @name Associations
*/ */
var Mixin = module.exports = function() {}; const Mixin = {
/**
// The logic for hasOne and belongsTo is exactly the same
var singleLinked = function (Type) {
return function(target, options) { // testhint options:none
if (!target.prototype || !(target.prototype instanceof this.sequelize.Model)) {
throw new Error(this.name + '.' + Utils.lowercaseFirst(Type.toString()) + ' called with something that\'s not a subclass of Sequelize.Model');
}
var source = this;
// Since this is a mixin, we'll need a unique variable name for hooks (since Model will override our hooks option)
options = options || {};
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
// the id is in the foreign table
var association = new Type(source, target, _.extend(options, source.options));
source.associations[association.associationAccessor] = association.injectAttributes();
if (association.mixin) {
association.mixin(source.prototype);
} else {
association.injectGetter(source.prototype);
association.injectSetter(source.prototype);
association.injectCreator(source.prototype);
}
return association;
};
};
/**
* Creates an association between this (the source) and the provided target. The foreign key is added on the target.
*
* Example: `User.hasOne(Profile)`. This will add userId to the profile table.
*
* @method hasOne
* @param {Model} target
* @param {object} [options]
* @param {boolean} [options.hooks=false] Set to true to run before-/afterDestroy hooks when an associated model is deleted because of a cascade. For example if `User.hasOne(Profile, {onDelete: 'cascade', hooks:true})`, the before-/afterDestroy hooks for profile will be called when a user is deleted. Otherwise the profile will be deleted without invoking any hooks
* @param {string} [options.as] The alias of this model, in singular form. See also the `name` option passed to `sequelize.define`. If you create multiple associations between the same tables, you should provide an alias to be able to distinguish between them. If you provide an alias when creating the association, you should provide the same alias when eager loading and when getting associated models. Defaults to the singularized name of target
* @param {string|object} [options.foreignKey] The name of the foreign key in the target table or an object representing the type definition for the foreign column (see `Sequelize.define` for syntax). When using an object, you can add a `name` property to set the name of the column. Defaults to the name of source + primary key of source
* @param {string} [options.onDelete='SET NULL|CASCADE'] SET NULL if foreignKey allows nulls, CASCADE if otherwise
* @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
*/
Mixin.hasOne = singleLinked(HasOne);
/**
* Creates an association between this (the source) and the provided target. The foreign key is added on the source.
*
* Example: `Profile.belongsTo(User)`. This will add userId to the profile table.
*
* @method belongsTo
* @param {Model} target
* @param {object} [options]
* @param {boolean} [options.hooks=false] Set to true to run before-/afterDestroy hooks when an associated model is deleted because of a cascade. For example if `User.hasOne(Profile, {onDelete: 'cascade', hooks:true})`, the before-/afterDestroy hooks for profile will be called when a user is deleted. Otherwise the profile will be deleted without invoking any hooks
* @param {string} [options.as] The alias of this model, in singular form. See also the `name` option passed to `sequelize.define`. If you create multiple associations between the same tables, you should provide an alias to be able to distinguish between them. If you provide an alias when creating the association, you should provide the same alias when eager loading and when getting associated models. Defaults to the singularized name of target
* @param {string|object} [options.foreignKey] The name of the foreign key in the source table or an object representing the type definition for the foreign column (see `Sequelize.define` for syntax). When using an object, you can add a `name` property to set the name of the column. Defaults to the name of target + primary key of target
* @param {string} [options.targetKey] The name of the field to use as the key for the association in the target table. Defaults to the primary key of the target table
* @param {string} [options.onDelete='SET NULL|NO ACTION'] SET NULL if foreignKey allows nulls, NO ACTION if otherwise
* @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
*/
Mixin.belongsTo = singleLinked(BelongsTo);
/**
* Creates a 1:m association between this (the source) and the provided target. The foreign key is added on the target. * Creates a 1:m association between this (the source) and the provided target. The foreign key is added on the target.
* *
* Example: `User.hasMany(Profile)`. This will add userId to the profile table. * Example: `User.hasMany(Profile)`. This will add userId to the profile table.
...@@ -167,14 +102,14 @@ Mixin.belongsTo = singleLinked(BelongsTo); ...@@ -167,14 +102,14 @@ Mixin.belongsTo = singleLinked(BelongsTo);
* @param {string} [options.onUpdate='CASCADE'] * @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key. * @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
*/ */
Mixin.hasMany = function(target, options) { // testhint options:none hasMany(target, options) { // testhint options:none
if (!target.prototype || !(target.prototype instanceof this.sequelize.Model)) { if (!target.prototype || !(target.prototype instanceof this.sequelize.Model)) {
throw new Error(this.name + '.hasMany called with something that\'s not a subclass of Sequelize.Model'); throw new Error(this.name + '.hasMany called with something that\'s not a subclass of Sequelize.Model');
} }
var source = this; const source = this;
// Since this is a mixin, we'll need a unique variable name for hooks (since Model will override our hooks option) // Since this is a mixin, we'll need a unique letiable name for hooks (since Model will override our hooks option)
options = options || {}; options = options || {};
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks); options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks; options.useHooks = options.hooks;
...@@ -182,16 +117,16 @@ Mixin.hasMany = function(target, options) { // testhint options:none ...@@ -182,16 +117,16 @@ Mixin.hasMany = function(target, options) { // testhint options:none
options = _.extend(options, _.omit(source.options, ['hooks'])); options = _.extend(options, _.omit(source.options, ['hooks']));
// the id is in the foreign table or in a connecting table // the id is in the foreign table or in a connecting table
var association = new HasMany(source, target, options); const association = new HasMany(source, target, options);
source.associations[association.associationAccessor] = association; source.associations[association.associationAccessor] = association;
association.injectAttributes(); association.injectAttributes();
association.mixin(source.prototype); association.mixin(source.prototype);
return association; return association;
}; },
/** /**
* Create an N:M association with a join table. * Create an N:M association with a join table.
* *
* ```js * ```js
...@@ -202,7 +137,7 @@ Mixin.hasMany = function(target, options) { // testhint options:none ...@@ -202,7 +137,7 @@ Mixin.hasMany = function(target, options) { // testhint options:none
* *
* If you define a through model with custom attributes, these attributes can be set when adding / setting new associations in two ways. Consider users and projects from before with a join table that stores whether the project has been started yet: * If you define a through model with custom attributes, these attributes can be set when adding / setting new associations in two ways. Consider users and projects from before with a join table that stores whether the project has been started yet:
* ```js * ```js
* var UserProjects = sequelize.define('UserProjects', { * let UserProjects = sequelize.define('UserProjects', {
* started: Sequelize.BOOLEAN * started: Sequelize.BOOLEAN
* }) * })
* User.belongsToMany(Project, { through: UserProjects }) * User.belongsToMany(Project, { through: UserProjects })
...@@ -225,7 +160,7 @@ Mixin.hasMany = function(target, options) { // testhint options:none ...@@ -225,7 +160,7 @@ Mixin.hasMany = function(target, options) { // testhint options:none
* Similarly, when fetching through a join table with custom attributes, these attributes will be available as an object with the name of the through model. * Similarly, when fetching through a join table with custom attributes, these attributes will be available as an object with the name of the through model.
* ```js * ```js
* user.getProjects().then(function (projects) { * user.getProjects().then(function (projects) {
* var p1 = projects[0] * let p1 = projects[0]
* p1.UserProjects.started // Is this project started yet? * p1.UserProjects.started // Is this project started yet?
* }) * })
* ``` * ```
...@@ -246,14 +181,14 @@ Mixin.hasMany = function(target, options) { // testhint options:none ...@@ -246,14 +181,14 @@ Mixin.hasMany = function(target, options) { // testhint options:none
* @param {string} [options.onUpdate='CASCADE'] * @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key. * @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
*/ */
Mixin.belongsToMany = function(targetModel, options) { // testhint options:none belongsToMany(targetModel, options) { // testhint options:none
if (!targetModel.prototype || !(targetModel.prototype instanceof this.sequelize.Model)) { if (!targetModel.prototype || !(targetModel.prototype instanceof this.sequelize.Model)) {
throw new Error(this.name + '.belongsToMany called with something that\'s not a subclass of Sequelize.Model'); throw new Error(this.name + '.belongsToMany called with something that\'s not a subclass of Sequelize.Model');
} }
var sourceModel = this; const sourceModel = this;
// Since this is a mixin, we'll need a unique variable name for hooks (since Model will override our hooks option) // Since this is a mixin, we'll need a unique letiable name for hooks (since Model will override our hooks option)
options = options || {}; options = options || {};
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks); options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks; options.useHooks = options.hooks;
...@@ -261,7 +196,7 @@ Mixin.belongsToMany = function(targetModel, options) { // testhint options:none ...@@ -261,7 +196,7 @@ Mixin.belongsToMany = function(targetModel, options) { // testhint options:none
options = _.extend(options, _.omit(sourceModel.options, ['hooks', 'timestamps', 'scopes', 'defaultScope'])); options = _.extend(options, _.omit(sourceModel.options, ['hooks', 'timestamps', 'scopes', 'defaultScope']));
// the id is in the foreign table or in a connecting table // the id is in the foreign table or in a connecting table
var association = new BelongsToMany(sourceModel, targetModel, options); const association = new BelongsToMany(sourceModel, targetModel, options);
sourceModel.associations[association.associationAccessor] = association.injectAttributes(); sourceModel.associations[association.associationAccessor] = association.injectAttributes();
association.injectGetter(sourceModel.prototype); association.injectGetter(sourceModel.prototype);
...@@ -269,12 +204,12 @@ Mixin.belongsToMany = function(targetModel, options) { // testhint options:none ...@@ -269,12 +204,12 @@ Mixin.belongsToMany = function(targetModel, options) { // testhint options:none
association.injectCreator(sourceModel.prototype); association.injectCreator(sourceModel.prototype);
return association; return association;
}; },
Mixin.getAssociation = function(target, alias) { getAssociation(target, alias) {
for (var associationName in this.associations) { for (const associationName in this.associations) {
if (this.associations.hasOwnProperty(associationName)) { if (this.associations.hasOwnProperty(associationName)) {
var association = this.associations[associationName]; const association = this.associations[associationName];
if (association.target.name === target.name && (alias === undefined ? !association.isAliased : association.as === alias)) { if (association.target.name === target.name && (alias === undefined ? !association.isAliased : association.as === alias)) {
return association; return association;
...@@ -283,4 +218,74 @@ Mixin.getAssociation = function(target, alias) { ...@@ -283,4 +218,74 @@ Mixin.getAssociation = function(target, alias) {
} }
return null; return null;
}
}; };
// The logic for hasOne and belongsTo is exactly the same
function singleLinked(Type) {
return function(target, options) { // testhint options:none
if (!target.prototype || !(target.prototype instanceof this.sequelize.Model)) {
throw new Error(this.name + '.' + Utils.lowercaseFirst(Type.toString()) + ' called with something that\'s not a subclass of Sequelize.Model');
}
const source = this;
// Since this is a mixin, we'll need a unique letiable name for hooks (since Model will override our hooks option)
options = options || {};
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
// the id is in the foreign table
const association = new Type(source, target, _.extend(options, source.options));
source.associations[association.associationAccessor] = association.injectAttributes();
if (association.mixin) {
association.mixin(source.prototype);
} else {
association.injectGetter(source.prototype);
association.injectSetter(source.prototype);
association.injectCreator(source.prototype);
}
return association;
};
}
/**
* Creates an association between this (the source) and the provided target. The foreign key is added on the target.
*
* Example: `User.hasOne(Profile)`. This will add userId to the profile table.
*
* @method hasOne
* @param {Model} target
* @param {object} [options]
* @param {boolean} [options.hooks=false] Set to true to run before-/afterDestroy hooks when an associated model is deleted because of a cascade. For example if `User.hasOne(Profile, {onDelete: 'cascade', hooks:true})`, the before-/afterDestroy hooks for profile will be called when a user is deleted. Otherwise the profile will be deleted without invoking any hooks
* @param {string} [options.as] The alias of this model, in singular form. See also the `name` option passed to `sequelize.define`. If you create multiple associations between the same tables, you should provide an alias to be able to distinguish between them. If you provide an alias when creating the association, you should provide the same alias when eager loading and when getting associated models. Defaults to the singularized name of target
* @param {string|object} [options.foreignKey] The name of the foreign key in the target table or an object representing the type definition for the foreign column (see `Sequelize.define` for syntax). When using an object, you can add a `name` property to set the name of the column. Defaults to the name of source + primary key of source
* @param {string} [options.onDelete='SET NULL|CASCADE'] SET NULL if foreignKey allows nulls, CASCADE if otherwise
* @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
*/
Mixin.hasOne = singleLinked(HasOne);
/**
* Creates an association between this (the source) and the provided target. The foreign key is added on the source.
*
* Example: `Profile.belongsTo(User)`. This will add userId to the profile table.
*
* @method belongsTo
* @param {Model} target
* @param {object} [options]
* @param {boolean} [options.hooks=false] Set to true to run before-/afterDestroy hooks when an associated model is deleted because of a cascade. For example if `User.hasOne(Profile, {onDelete: 'cascade', hooks:true})`, the before-/afterDestroy hooks for profile will be called when a user is deleted. Otherwise the profile will be deleted without invoking any hooks
* @param {string} [options.as] The alias of this model, in singular form. See also the `name` option passed to `sequelize.define`. If you create multiple associations between the same tables, you should provide an alias to be able to distinguish between them. If you provide an alias when creating the association, you should provide the same alias when eager loading and when getting associated models. Defaults to the singularized name of target
* @param {string|object} [options.foreignKey] The name of the foreign key in the source table or an object representing the type definition for the foreign column (see `Sequelize.define` for syntax). When using an object, you can add a `name` property to set the name of the column. Defaults to the name of target + primary key of target
* @param {string} [options.targetKey] The name of the field to use as the key for the association in the target table. Defaults to the primary key of the target table
* @param {string} [options.onDelete='SET NULL|NO ACTION'] SET NULL if foreignKey allows nulls, NO ACTION if otherwise
* @param {string} [options.onUpdate='CASCADE']
* @param {boolean} [options.constraints=true] Should on update and on delete constraints be enabled on the foreign key.
*/
Mixin.belongsTo = singleLinked(BelongsTo);
module.exports = Mixin;
module.exports.Mixin = Mixin;
module.exports.default = Mixin;
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!