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

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');
, 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-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;
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!