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

Commit 194ff2c7 by Felix Becker Committed by Jan Aagaard Meier

ES6 refactor: Model (#6039)

* ES6 refactor of model.js

* ES6 refactor of attribute.js

classes, export default
1 parent 6177a95d
Showing with 458 additions and 568 deletions
'use strict'; 'use strict';
var Utils = require('./utils') const Utils = require('./utils');
, BelongsTo = require('./associations/belongs-to') const BelongsTo = require('./associations/belongs-to');
, BelongsToMany = require('./associations/belongs-to-many') const BelongsToMany = require('./associations/belongs-to-many');
, InstanceValidator = require('./instance-validator') const InstanceValidator = require('./instance-validator');
, QueryTypes = require('./query-types') const QueryTypes = require('./query-types');
, sequelizeErrors = require('./errors') const sequelizeErrors = require('./errors');
, Dottie = require('dottie') const Dottie = require('dottie');
, Promise = require('./promise') const Promise = require('./promise');
, _ = require('lodash') const _ = require('lodash');
, Association = require('./associations/base') const Association = require('./associations/base');
, HasMany = require('./associations/has-many') const HasMany = require('./associations/has-many');
, DataTypes = require('./data-types') const DataTypes = require('./data-types');
, Hooks = require('./hooks') const Hooks = require('./hooks');
, associationsMixin = require('./associations/mixin') const associationsMixin = require('./associations/mixin');
, defaultsOptions = { raw: true }; const defaultsOptions = { raw: true };
/** /**
* A Model represents a table in the database. Instances of this class represent a database row. * A Model represents a table in the database. Instances of this class represent a database row.
...@@ -58,9 +58,9 @@ class Model { ...@@ -58,9 +58,9 @@ class Model {
// This should be handled before handling where conditions because of logic with returns // This should be handled before handling where conditions because of logic with returns
// otherwise this code will never run on includes of a already conditionable where // otherwise this code will never run on includes of a already conditionable where
if (options.include) { if (options.include) {
options.include.forEach(function(include) { for (const include of options.include) {
this._paranoidClause(include.model, include); this._paranoidClause(include.model, include);
}.bind(this)); }
} }
if (!model.options.timestamps || !model.options.paranoid || options.paranoid === false) { if (!model.options.timestamps || !model.options.paranoid || options.paranoid === false) {
...@@ -68,10 +68,10 @@ class Model { ...@@ -68,10 +68,10 @@ class Model {
return options; return options;
} }
var deletedAtCol = model._timestampAttributes.deletedAt const deletedAtCol = model._timestampAttributes.deletedAt;
, deletedAtAttribute = model.rawAttributes[deletedAtCol] const deletedAtAttribute = model.rawAttributes[deletedAtCol];
, deletedAtObject = {} const deletedAtObject = {};
, deletedAtDefaultValue = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null; let deletedAtDefaultValue = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null;
deletedAtDefaultValue = deletedAtDefaultValue || { $or: { $gte: model.sequelize.literal('CURRENT_TIMESTAMP'), $eq: null } }; deletedAtDefaultValue = deletedAtDefaultValue || { $or: { $gte: model.sequelize.literal('CURRENT_TIMESTAMP'), $eq: null } };
...@@ -87,14 +87,12 @@ class Model { ...@@ -87,14 +87,12 @@ class Model {
} }
static _addOptionalClassMethods() { static _addOptionalClassMethods() {
var self = this; Utils._.each(this.options.classMethods || {}, (fct, name) => { this[name] = fct; });
Utils._.each(this.options.classMethods || {}, function(fct, name) { self[name] = fct; });
} }
static _addDefaultAttributes() { static _addDefaultAttributes() {
var self = this const tail = {};
, tail = {} let head = {};
, head = {};
// Add id if no primary key was manually added to definition // Add id if no primary key was manually added to definition
// Can't use this.primaryKeys here, since this function is called before PKs are identified // Can't use this.primaryKeys here, since this function is called before PKs are identified
...@@ -136,40 +134,40 @@ class Model { ...@@ -136,40 +134,40 @@ class Model {
}; };
} }
var existingAttributes = Utils._.clone(self.rawAttributes); const existingAttributes = Utils._.clone(this.rawAttributes);
self.rawAttributes = {}; this.rawAttributes = {};
Utils._.each(head, function(value, attr) { Utils._.each(head, (value, attr) => {
self.rawAttributes[attr] = value; this.rawAttributes[attr] = value;
}); });
Utils._.each(existingAttributes, function(value, attr) { Utils._.each(existingAttributes, (value, attr) => {
self.rawAttributes[attr] = value; this.rawAttributes[attr] = value;
}); });
Utils._.each(tail, function(value, attr) { Utils._.each(tail, (value, attr) => {
if (Utils._.isUndefined(self.rawAttributes[attr])) { if (Utils._.isUndefined(this.rawAttributes[attr])) {
self.rawAttributes[attr] = value; this.rawAttributes[attr] = value;
} }
}); });
if (!Object.keys(this.primaryKeys).length) { if (!Object.keys(this.primaryKeys).length) {
self.primaryKeys.id = self.rawAttributes.id; this.primaryKeys.id = this.rawAttributes.id;
} }
} }
static _findAutoIncrementField() { static _findAutoIncrementField() {
var fields = this.QueryGenerator.findAutoIncrementField(this); const fields = this.QueryGenerator.findAutoIncrementField(this);
this.autoIncrementField = null; this.autoIncrementField = null;
fields.forEach(function(field) { for (const field of fields) {
if (this.autoIncrementField) { if (this.autoIncrementField) {
throw new Error('Invalid Instance definition. Only one autoincrement field allowed.'); throw new Error('Invalid Instance definition. Only one autoincrement field allowed.');
} else { } else {
this.autoIncrementField = field; this.autoIncrementField = field;
} }
}.bind(this)); }
} }
static _conformOptions(options, self) { static _conformOptions(options, self) {
...@@ -189,15 +187,11 @@ class Model { ...@@ -189,15 +187,11 @@ class Model {
} }
// convert all included elements to { model: Model } form // convert all included elements to { model: Model } form
options.include = options.include.map(function(include) { options.include = options.include.map(include => this._conformInclude(include, self));
include = this._conformInclude(include, self);
return include;
}.bind(this));
} }
static _conformInclude(include, self) { static _conformInclude(include, self) {
var model; let model;
if (include._pseudo) return include; if (include._pseudo) return include;
...@@ -208,7 +202,7 @@ class Model { ...@@ -208,7 +202,7 @@ class Model {
model = include.target; model = include.target;
} }
include = { model: model, association: include, as: include.as }; include = { model, association: include, as: include.as };
} else if (include.prototype && include.prototype instanceof Model) { } else if (include.prototype && include.prototype instanceof Model) {
include = { model: include }; include = { model: include };
} else if (_.isPlainObject(include)) { } else if (_.isPlainObject(include)) {
...@@ -239,7 +233,7 @@ class Model { ...@@ -239,7 +233,7 @@ class Model {
static _expandIncludeAllElement(includes, include) { static _expandIncludeAllElement(includes, include) {
// check 'all' attribute provided is valid // check 'all' attribute provided is valid
var all = include.all; let all = include.all;
delete include.all; delete include.all;
if (all !== true) { if (all !== true) {
...@@ -247,7 +241,7 @@ class Model { ...@@ -247,7 +241,7 @@ class Model {
all = [all]; all = [all];
} }
var validTypes = { const validTypes = {
BelongsTo: true, BelongsTo: true,
HasOne: true, HasOne: true,
HasMany: true, HasMany: true,
...@@ -256,14 +250,14 @@ class Model { ...@@ -256,14 +250,14 @@ class Model {
Many: ['HasMany'] Many: ['HasMany']
}; };
for (var i = 0; i < all.length; i++) { for (let i = 0; i < all.length; i++) {
var type = all[i]; const type = all[i];
if (type === 'All') { if (type === 'All') {
all = true; all = true;
break; break;
} }
var types = validTypes[type]; const types = validTypes[type];
if (!types) { if (!types) {
throw new Error('include all \'' + type + '\' is not valid - must be BelongsTo, HasOne, HasMany, One, Has, Many or All'); throw new Error('include all \'' + type + '\' is not valid - must be BelongsTo, HasOne, HasMany, One, Has, Many or All');
} }
...@@ -272,7 +266,7 @@ class Model { ...@@ -272,7 +266,7 @@ class Model {
// replace type placeholder e.g. 'One' with it's constituent types e.g. 'HasOne', 'BelongsTo' // replace type placeholder e.g. 'One' with it's constituent types e.g. 'HasOne', 'BelongsTo'
all.splice(i, 1); all.splice(i, 1);
i--; i--;
for (var j = 0; j < types.length; j++) { for (let j = 0; j < types.length; j++) {
if (all.indexOf(types[j]) === -1) { if (all.indexOf(types[j]) === -1) {
all.unshift(types[j]); all.unshift(types[j]);
i++; i++;
...@@ -283,7 +277,7 @@ class Model { ...@@ -283,7 +277,7 @@ class Model {
} }
// add all associations of types specified to includes // add all associations of types specified to includes
var nested = include.nested; const nested = include.nested;
if (nested) { if (nested) {
delete include.nested; delete include.nested;
...@@ -294,18 +288,18 @@ class Model { ...@@ -294,18 +288,18 @@ class Model {
} }
} }
var used = []; const used = [];
(function addAllIncludes(parent, includes) { (function addAllIncludes(parent, includes) {
Utils._.forEach(parent.associations, function(association) { Utils._.forEach(parent.associations, association => {
if (all !== true && all.indexOf(association.associationType) === -1) { if (all !== true && all.indexOf(association.associationType) === -1) {
return; return;
} }
// check if model already included, and skip if so // check if model already included, and skip if so
var model = association.target; const model = association.target;
var as = association.options.as; const as = association.options.as;
var predicate = {model: model}; const predicate = {model};
if (as) { if (as) {
// We only add 'as' to the predicate if it actually exists // We only add 'as' to the predicate if it actually exists
predicate.as = as; predicate.as = as;
...@@ -322,7 +316,7 @@ class Model { ...@@ -322,7 +316,7 @@ class Model {
used.push(parent); used.push(parent);
// include this model // include this model
var thisInclude = Utils.cloneDeep(include); const thisInclude = Utils.cloneDeep(include);
thisInclude.model = model; thisInclude.model = model;
if (as) { if (as) {
thisInclude.as = as; thisInclude.as = as;
...@@ -355,7 +349,7 @@ class Model { ...@@ -355,7 +349,7 @@ class Model {
options.topLimit = options.limit; options.topLimit = options.limit;
} }
options.include = options.include.map(function (include) { options.include = options.include.map(include => {
include = this._conformInclude(include); include = this._conformInclude(include);
include.parent = options; include.parent = options;
...@@ -373,9 +367,9 @@ class Model { ...@@ -373,9 +367,9 @@ class Model {
options.hasWhere = options.hasWhere || include.hasWhere || !!include.where; options.hasWhere = options.hasWhere || include.hasWhere || !!include.where;
return include; return include;
}.bind(this)); });
options.include.forEach(function (include) { for (const include of options.include) {
include.hasParentWhere = options.hasParentWhere || !!options.where; include.hasParentWhere = options.hasParentWhere || !!options.where;
include.hasParentRequired = options.hasParentRequired || !!options.required; include.hasParentRequired = options.hasParentRequired || !!options.required;
...@@ -420,9 +414,7 @@ class Model { ...@@ -420,9 +414,7 @@ class Model {
if (include.association.isSingleAssociation || include.hasSingleAssociation) { if (include.association.isSingleAssociation || include.hasSingleAssociation) {
options.hasSingleAssociation = true; options.hasSingleAssociation = true;
} }
}
return include;
});
if (options.topModel === options.model && options.subQuery === undefined) { if (options.topModel === options.model && options.subQuery === undefined) {
options.subQuery = false; options.subQuery = false;
...@@ -442,9 +434,9 @@ class Model { ...@@ -442,9 +434,9 @@ class Model {
include.originalAttributes = include.attributes.slice(0); include.originalAttributes = include.attributes.slice(0);
if (include.attributes.length) { if (include.attributes.length) {
_.each(include.model.primaryKeys, function (attr, key) { _.each(include.model.primaryKeys, (attr, key) => {
// Include the primary key if its not already take - take into account that the pk might be aliassed (due to a .field prop) // Include the primary key if its not already take - take into account that the pk might be aliassed (due to a .field prop)
if (!_.some(include.attributes, function (includeAttr) { if (!_.some(include.attributes, (includeAttr) => {
if (attr.field !== key) { if (attr.field !== key) {
return Array.isArray(includeAttr) && includeAttr[0] === attr.field && includeAttr[1] === key; return Array.isArray(includeAttr) && includeAttr[0] === attr.field && includeAttr[1] === key;
} }
...@@ -465,10 +457,10 @@ class Model { ...@@ -465,10 +457,10 @@ class Model {
} }
// check if the current Model is actually associated with the passed Model - or it's a pseudo include // check if the current Model is actually associated with the passed Model - or it's a pseudo include
var association = include.association || this.getAssociation(include.model, include.as); const association = include.association || this.getAssociation(include.model, include.as);
if (!association) { if (!association) {
var msg = include.model.name; let msg = include.model.name;
if (include.as) { if (include.as) {
msg += ' (' + include.as + ')'; msg += ' (' + include.as + ')';
...@@ -485,7 +477,7 @@ class Model { ...@@ -485,7 +477,7 @@ class Model {
// If through, we create a pseudo child include, to ease our parsing later on // If through, we create a pseudo child include, to ease our parsing later on
if (include.association.through && Object(include.association.through.model) === include.association.through.model) { if (include.association.through && Object(include.association.through.model) === include.association.through.model) {
if (!include.include) include.include = []; if (!include.include) include.include = [];
var through = include.association.through; const through = include.association.through;
include.through = Utils._.defaults(include.through || {}, { include.through = Utils._.defaults(include.through || {}, {
model: through.model, model: through.model,
...@@ -507,7 +499,7 @@ class Model { ...@@ -507,7 +499,7 @@ class Model {
} }
// include.model may be the main model, while the association target may be scoped - thus we need to look at association.target/source // include.model may be the main model, while the association target may be scoped - thus we need to look at association.target/source
var model; let model;
if (include.model.scoped === true) { if (include.model.scoped === true) {
// If the passed model is already scoped, keep that // If the passed model is already scoped, keep that
model = include.model; model = include.model;
...@@ -558,13 +550,13 @@ class Model { ...@@ -558,13 +550,13 @@ class Model {
} }
static _expandIncludeAll(options) { static _expandIncludeAll(options) {
var includes = options.include; const includes = options.include;
if (!includes) { if (!includes) {
return; return;
} }
for (var index = 0; index < includes.length; index++) { for (let index = 0; index < includes.length; index++) {
var include = includes[index]; const include = includes[index];
if (include.all) { if (include.all) {
includes.splice(index, 1); includes.splice(index, 1);
...@@ -574,13 +566,12 @@ class Model { ...@@ -574,13 +566,12 @@ class Model {
} }
} }
Utils._.forEach(includes, function(include) { Utils._.forEach(includes, include => {
this._expandIncludeAll.call(include.model, include); this._expandIncludeAll.call(include.model, include);
}.bind(this)); });
} }
static init(attributes, options, modelManager) { static init(attributes, options, modelManager) {
var self = this;
this.options = Utils._.extend({ this.options = Utils._.extend({
timestamps: true, timestamps: true,
...@@ -603,7 +594,7 @@ class Model { ...@@ -603,7 +594,7 @@ class Model {
this.associations = {}; this.associations = {};
this.modelManager = null; this.modelManager = null;
this.options.hooks = _.mapValues(this.replaceHookAliases(this.options.hooks), function (hooks) { this.options.hooks = _.mapValues(this.replaceHookAliases(this.options.hooks), hooks => {
if (!Array.isArray(hooks)) hooks = [hooks]; if (!Array.isArray(hooks)) hooks = [hooks];
return hooks; return hooks;
}); });
...@@ -621,7 +612,7 @@ class Model { ...@@ -621,7 +612,7 @@ class Model {
this.$schemaDelimiter = this.options.schemaDelimiter; this.$schemaDelimiter = this.options.schemaDelimiter;
// error check options // error check options
_.each(options.validate, function(validator, validatorType) { _.each(options.validate, (validator, validatorType) => {
if (_.includes(Utils._.keys(attributes), validatorType)) { if (_.includes(Utils._.keys(attributes), validatorType)) {
throw new Error('A model validator function must not have the same name as a field. Model: ' + this.name + ', field/validation name: ' + validatorType); throw new Error('A model validator function must not have the same name as a field. Model: ' + this.name + ', field/validation name: ' + validatorType);
} }
...@@ -629,9 +620,10 @@ class Model { ...@@ -629,9 +620,10 @@ class Model {
if (!_.isFunction(validator)) { if (!_.isFunction(validator)) {
throw new Error('Members of the validate option must be functions. Model: ' + this.name + ', error with validate member ' + validatorType); throw new Error('Members of the validate option must be functions. Model: ' + this.name + ', error with validate member ' + validatorType);
} }
}.bind(this)); });
this.attributes = this.rawAttributes = _.mapValues(attributes, (attribute, name) => { this.attributes = this.rawAttributes = _.mapValues(attributes, (attribute, name) => {
attribute = this.sequelize.normalizeAttribute(attribute); attribute = this.sequelize.normalizeAttribute(attribute);
if (attribute.references && attribute.references.model && attribute.references.model.prototype instanceof Model) { if (attribute.references && attribute.references.model && attribute.references.model.prototype instanceof Model) {
...@@ -667,13 +659,11 @@ class Model { ...@@ -667,13 +659,11 @@ class Model {
this._readOnlyAttributes = Utils._.values(this._timestampAttributes); this._readOnlyAttributes = Utils._.values(this._timestampAttributes);
this._hasReadOnlyAttributes = this._readOnlyAttributes && this._readOnlyAttributes.length; this._hasReadOnlyAttributes = this._readOnlyAttributes && this._readOnlyAttributes.length;
this._isReadOnlyAttribute = Utils._.memoize(function(key) { this._isReadOnlyAttribute = Utils._.memoize(key => this._hasReadOnlyAttributes && this._readOnlyAttributes.indexOf(key) !== -1);
return self._hasReadOnlyAttributes && self._readOnlyAttributes.indexOf(key) !== -1;
});
if (this.options.instanceMethods) { if (this.options.instanceMethods) {
Utils._.each(this.options.instanceMethods, function(fct, name) { Utils._.each(this.options.instanceMethods, (fct, name) => {
self.prototype[name] = fct; this.prototype[name] = fct;
}); });
} }
...@@ -688,11 +678,11 @@ class Model { ...@@ -688,11 +678,11 @@ class Model {
this._conformOptions(this.$scope, this); this._conformOptions(this.$scope, this);
} }
_.each(this.options.scopes, function (scope) { _.each(this.options.scopes, scope => {
if (_.isPlainObject(scope)) { if (_.isPlainObject(scope)) {
this._conformOptions(scope, this); this._conformOptions(scope, this);
} }
}.bind(this)); });
this.options.indexes = this.options.indexes.map(this.$conformIndex); this.options.indexes = this.options.indexes.map(this.$conformIndex);
...@@ -713,18 +703,17 @@ class Model { ...@@ -713,18 +703,17 @@ class Model {
} }
static refreshAttributes() { static refreshAttributes() {
var self = this const attributeManipulation = {};
, attributeManipulation = {};
this.prototype._customGetters = {}; this.prototype._customGetters = {};
this.prototype._customSetters = {}; this.prototype._customSetters = {};
Utils._.each(['get', 'set'], function(type) { Utils._.each(['get', 'set'], type => {
var opt = type + 'terMethods' const opt = type + 'terMethods';
, funcs = Utils._.clone(Utils._.isObject(self.options[opt]) ? self.options[opt] : {}) const funcs = Utils._.clone(Utils._.isObject(this.options[opt]) ? this.options[opt] : {});
, _custom = type === 'get' ? self.prototype._customGetters : self.prototype._customSetters; const _custom = type === 'get' ? this.prototype._customGetters : this.prototype._customSetters;
Utils._.each(funcs, function(method, attribute) { Utils._.each(funcs, (method, attribute) => {
_custom[attribute] = method; _custom[attribute] = method;
if (type === 'get') { if (type === 'get') {
...@@ -739,7 +728,7 @@ class Model { ...@@ -739,7 +728,7 @@ class Model {
} }
}); });
Utils._.each(self.rawAttributes, function(options, attribute) { Utils._.each(this.rawAttributes, (options, attribute) => {
if (options.hasOwnProperty(type)) { if (options.hasOwnProperty(type)) {
_custom[attribute] = options[type]; _custom[attribute] = options[type];
} }
...@@ -756,7 +745,7 @@ class Model { ...@@ -756,7 +745,7 @@ class Model {
} }
}); });
Utils._.each(funcs, function(fct, name) { Utils._.each(funcs, (fct, name) => {
if (!attributeManipulation[name]) { if (!attributeManipulation[name]) {
attributeManipulation[name] = { attributeManipulation[name] = {
configurable: true configurable: true
...@@ -779,12 +768,12 @@ class Model { ...@@ -779,12 +768,12 @@ class Model {
this.fieldRawAttributesMap = {}; this.fieldRawAttributesMap = {};
this.primaryKeys = {}; this.primaryKeys = {};
self.options.uniqueKeys = {}; this.options.uniqueKeys = {};
_.each(this.rawAttributes, function(definition, name) { _.each(this.rawAttributes, (definition, name) => {
definition.type = self.sequelize.normalizeDataType(definition.type); definition.type = this.sequelize.normalizeDataType(definition.type);
definition.Model = self; definition.Model = this;
definition.fieldName = name; definition.fieldName = name;
definition._modelAttribute = true; definition._modelAttribute = true;
...@@ -793,57 +782,57 @@ class Model { ...@@ -793,57 +782,57 @@ class Model {
} }
if (definition.primaryKey === true) { if (definition.primaryKey === true) {
self.primaryKeys[name] = definition; this.primaryKeys[name] = definition;
} }
self.fieldRawAttributesMap[definition.field] = definition; this.fieldRawAttributesMap[definition.field] = definition;
if (definition.type instanceof DataTypes.BOOLEAN) { if (definition.type instanceof DataTypes.BOOLEAN) {
self._booleanAttributes.push(name); this._booleanAttributes.push(name);
} else if (definition.type instanceof DataTypes.DATE || definition.type instanceof DataTypes.DATEONLY) { } else if (definition.type instanceof DataTypes.DATE || definition.type instanceof DataTypes.DATEONLY) {
self._dateAttributes.push(name); this._dateAttributes.push(name);
} else if (definition.type instanceof DataTypes.HSTORE || DataTypes.ARRAY.is(definition.type, DataTypes.HSTORE)) { } else if (definition.type instanceof DataTypes.HSTORE || DataTypes.ARRAY.is(definition.type, DataTypes.HSTORE)) {
self._hstoreAttributes.push(name); this._hstoreAttributes.push(name);
} else if (definition.type instanceof DataTypes.RANGE || DataTypes.ARRAY.is(definition.type, DataTypes.RANGE)) { } else if (definition.type instanceof DataTypes.RANGE || DataTypes.ARRAY.is(definition.type, DataTypes.RANGE)) {
self._rangeAttributes.push(name); this._rangeAttributes.push(name);
} else if (definition.type instanceof DataTypes.JSON) { } else if (definition.type instanceof DataTypes.JSON) {
self._jsonAttributes.push(name); this._jsonAttributes.push(name);
} else if (definition.type instanceof DataTypes.VIRTUAL) { } else if (definition.type instanceof DataTypes.VIRTUAL) {
self._virtualAttributes.push(name); this._virtualAttributes.push(name);
} else if (definition.type instanceof DataTypes.GEOMETRY) { } else if (definition.type instanceof DataTypes.GEOMETRY) {
self._geometryAttributes.push(name); this._geometryAttributes.push(name);
} }
if (definition.hasOwnProperty('defaultValue')) { if (definition.hasOwnProperty('defaultValue')) {
self._defaultValues[name] = Utils._.partial(Utils.toDefaultValue, definition.defaultValue); this._defaultValues[name] = Utils._.partial(Utils.toDefaultValue, definition.defaultValue);
} }
if (definition.hasOwnProperty('unique') && definition.unique !== false) { if (definition.hasOwnProperty('unique') && definition.unique !== false) {
var idxName; let idxName;
if (typeof definition.unique === 'object' && definition.unique.hasOwnProperty('name')) { if (typeof definition.unique === 'object' && definition.unique.hasOwnProperty('name')) {
idxName = definition.unique.name; idxName = definition.unique.name;
} else if (typeof definition.unique === 'string') { } else if (typeof definition.unique === 'string') {
idxName = definition.unique; idxName = definition.unique;
} else { } else {
idxName = self.tableName + '_' + name + '_unique'; idxName = this.tableName + '_' + name + '_unique';
} }
var idx = self.options.uniqueKeys[idxName] || { fields: [] }; let idx = this.options.uniqueKeys[idxName] || { fields: [] };
idx = idx || {fields: [], msg: null}; idx = idx || {fields: [], msg: null};
idx.fields.push(definition.field); idx.fields.push(definition.field);
idx.msg = idx.msg || definition.unique.msg || null; idx.msg = idx.msg || definition.unique.msg || null;
idx.name = idxName || false; idx.name = idxName || false;
idx.column = name; idx.column = name;
self.options.uniqueKeys[idxName] = idx; this.options.uniqueKeys[idxName] = idx;
} }
if (definition.hasOwnProperty('validate')) { if (definition.hasOwnProperty('validate')) {
self.prototype.validators[name] = definition.validate; this.prototype.validators[name] = definition.validate;
} }
if (definition.index === true && definition.type instanceof DataTypes.JSONB) { if (definition.index === true && definition.type instanceof DataTypes.JSONB) {
self.options.indexes.push({ this.options.indexes.push({
fields: [definition.field || name], fields: [definition.field || name],
using: 'gin' using: 'gin'
}); });
...@@ -852,7 +841,7 @@ class Model { ...@@ -852,7 +841,7 @@ class Model {
} }
}); });
// Create a map of field to attribute names // Create a map of field to attribute names
this.fieldAttributeMap = Utils._.reduce(this.fieldRawAttributesMap, function(map, value, key) { this.fieldAttributeMap = Utils._.reduce(this.fieldRawAttributesMap, (map, value, key) => {
if (key !== value.fieldName) { if (key !== value.fieldName) {
map[key] = value.fieldName; map[key] = value.fieldName;
} }
...@@ -862,39 +851,25 @@ class Model { ...@@ -862,39 +851,25 @@ class Model {
this.uniqueKeys = this.options.uniqueKeys; this.uniqueKeys = this.options.uniqueKeys;
this._hasBooleanAttributes = !!this._booleanAttributes.length; this._hasBooleanAttributes = !!this._booleanAttributes.length;
this._isBooleanAttribute = Utils._.memoize(function(key) { this._isBooleanAttribute = Utils._.memoize(key => this._booleanAttributes.indexOf(key) !== -1);
return self._booleanAttributes.indexOf(key) !== -1;
});
this._hasDateAttributes = !!this._dateAttributes.length; this._hasDateAttributes = !!this._dateAttributes.length;
this._isDateAttribute = Utils._.memoize(function(key) { this._isDateAttribute = Utils._.memoize(key => this._dateAttributes.indexOf(key) !== -1);
return self._dateAttributes.indexOf(key) !== -1;
});
this._hasHstoreAttributes = !!this._hstoreAttributes.length; this._hasHstoreAttributes = !!this._hstoreAttributes.length;
this._isHstoreAttribute = Utils._.memoize(function(key) { this._isHstoreAttribute = Utils._.memoize(key => this._hstoreAttributes.indexOf(key) !== -1);
return self._hstoreAttributes.indexOf(key) !== -1;
});
this._hasRangeAttributes = !!this._rangeAttributes.length; this._hasRangeAttributes = !!this._rangeAttributes.length;
this._isRangeAttribute = Utils._.memoize(function(key) { this._isRangeAttribute = Utils._.memoize(key => this._rangeAttributes.indexOf(key) !== -1);
return self._rangeAttributes.indexOf(key) !== -1;
});
this._hasJsonAttributes = !!this._jsonAttributes.length; this._hasJsonAttributes = !!this._jsonAttributes.length;
this._isJsonAttribute = Utils._.memoize(function(key) { this._isJsonAttribute = Utils._.memoize(key => this._jsonAttributes.indexOf(key) !== -1);
return self._jsonAttributes.indexOf(key) !== -1;
});
this._hasVirtualAttributes = !!this._virtualAttributes.length; this._hasVirtualAttributes = !!this._virtualAttributes.length;
this._isVirtualAttribute = Utils._.memoize(function(key) { this._isVirtualAttribute = Utils._.memoize(key => this._virtualAttributes.indexOf(key) !== -1);
return self._virtualAttributes.indexOf(key) !== -1;
});
this._hasGeometryAttributes = !!this._geometryAttributes.length; this._hasGeometryAttributes = !!this._geometryAttributes.length;
this._isGeometryAttribute = Utils._.memoize(function(key) { this._isGeometryAttribute = Utils._.memoize(key => this._geometryAttributes.indexOf(key) !== -1);
return self._geometryAttributes.indexOf(key) !== -1;
});
this._hasDefaultValues = !Utils._.isEmpty(this._defaultValues); this._hasDefaultValues = !Utils._.isEmpty(this._defaultValues);
...@@ -904,22 +879,20 @@ class Model { ...@@ -904,22 +879,20 @@ class Model {
this.prototype._hasCustomGetters = Object.keys(this.prototype._customGetters).length; this.prototype._hasCustomGetters = Object.keys(this.prototype._customGetters).length;
this.prototype._hasCustomSetters = Object.keys(this.prototype._customSetters).length; this.prototype._hasCustomSetters = Object.keys(this.prototype._customSetters).length;
Object.keys(attributeManipulation).forEach((function(key){ for (const key of Object.keys(attributeManipulation)) {
if (Model.prototype.hasOwnProperty(key)) { if (Model.prototype.hasOwnProperty(key)) {
this.sequelize.log('Not overriding built-in method from model attribute: ' + key); this.sequelize.log('Not overriding built-in method from model attribute: ' + key);
return; continue;
} }
Object.defineProperty(this.prototype, key, attributeManipulation[key]); Object.defineProperty(this.prototype, key, attributeManipulation[key]);
}).bind(this)); }
this.prototype.rawAttributes = this.rawAttributes; this.prototype.rawAttributes = this.rawAttributes;
this.prototype.attributes = Object.keys(this.prototype.rawAttributes); this.prototype.attributes = Object.keys(this.prototype.rawAttributes);
this.prototype._isAttribute = Utils._.memoize(function(key) { this.prototype._isAttribute = Utils._.memoize(key => this.prototype.attributes.indexOf(key) !== -1);
return self.prototype.attributes.indexOf(key) !== -1;
});
// Primary key convenience variables // Primary key convenience constiables
this.primaryKeyAttributes = Object.keys(this.primaryKeys); this.primaryKeyAttributes = Object.keys(this.primaryKeys);
this.primaryKeyAttribute = this.primaryKeyAttributes[0]; this.primaryKeyAttribute = this.primaryKeyAttributes[0];
if (this.primaryKeyAttribute) { if (this.primaryKeyAttribute) {
...@@ -929,9 +902,7 @@ class Model { ...@@ -929,9 +902,7 @@ class Model {
this.primaryKeyCount = this.primaryKeyAttributes.length; this.primaryKeyCount = this.primaryKeyAttributes.length;
this._hasPrimaryKeys = this.options.hasPrimaryKeys = this.hasPrimaryKeys = this.primaryKeyCount > 0; this._hasPrimaryKeys = this.options.hasPrimaryKeys = this.hasPrimaryKeys = this.primaryKeyCount > 0;
this._isPrimaryKey = Utils._.memoize(function(key) { this._isPrimaryKey = Utils._.memoize(key => this.primaryKeyAttributes.indexOf(key) !== -1);
return self.primaryKeyAttributes.indexOf(key) !== -1;
});
} }
...@@ -953,42 +924,37 @@ class Model { ...@@ -953,42 +924,37 @@ class Model {
options = _.extend({}, this.options, options); options = _.extend({}, this.options, options);
options.hooks = options.hooks === undefined ? true : !!options.hooks; options.hooks = options.hooks === undefined ? true : !!options.hooks;
var self = this const attributes = this.tableAttributes;
, attributes = this.tableAttributes;
return Promise.try(function () { return Promise.try(() => {
if (options.hooks) { if (options.hooks) {
return self.runHooks('beforeSync', options); return this.runHooks('beforeSync', options);
} }
}).then(function () { }).then(() => {
if (options.force) { if (options.force) {
return self.drop(options); return this.drop(options);
} }
}).then(function () { })
return self.QueryInterface.createTable(self.getTableName(options), attributes, options, self); .then(() => this.QueryInterface.createTable(this.getTableName(options), attributes, options, this))
}).then(function () { .then(() => this.QueryInterface.showIndex(this.getTableName(options), options))
return self.QueryInterface.showIndex(self.getTableName(options), options); .then(indexes => {
}).then(function (indexes) {
// Assign an auto-generated name to indexes which are not named by the user // Assign an auto-generated name to indexes which are not named by the user
self.options.indexes = self.QueryInterface.nameIndexes(self.options.indexes, self.tableName); this.options.indexes = this.QueryInterface.nameIndexes(this.options.indexes, this.tableName);
indexes = _.filter(self.options.indexes, function (item1) { indexes = _.filter(this.options.indexes, item1 => !_.some(indexes, item2 => item1.name === item2.name));
return !_.some(indexes, function (item2) {
return item1.name === item2.name;
});
});
return Promise.map(indexes, function (index) { return Promise.map(indexes, index => this.QueryInterface.addIndex(
return self.QueryInterface.addIndex( this.getTableName(options),
self.getTableName(options), _.assign({
_.assign({logging: options.logging, logging: options.logging,
benchmark: options.benchmark, benchmark: options.benchmark,
transaction: options.transaction}, index), transaction: options.transaction
self.tableName); }, index),
}); this.tableName
}).then(function () { ));
}).then(() => {
if (options.hooks) { if (options.hooks) {
return self.runHooks('afterSync', options); return this.runHooks('afterSync', options);
} }
}).return(this); }).return(this);
} }
...@@ -1031,7 +997,7 @@ class Model { ...@@ -1031,7 +997,7 @@ class Model {
*/ */
static schema(schema, options) { // testhint options:none static schema(schema, options) { // testhint options:none
var clone = class extends this {}; const clone = class extends this {};
Object.defineProperty(clone, 'name', {value: this.name}); Object.defineProperty(clone, 'name', {value: this.name});
clone.$schema = schema; clone.$schema = schema;
...@@ -1100,7 +1066,7 @@ class Model { ...@@ -1100,7 +1066,7 @@ class Model {
/** /**
* Apply a scope created in `define` to the model. First let's look at how to create scopes: * Apply a scope created in `define` to the model. First let's look at how to create scopes:
* ```js * ```js
* var Model = sequelize.define('model', attributes, { * const Model = sequelize.define('model', attributes, {
* defaultScope: { * defaultScope: {
* where: { * where: {
* username: 'dan' * username: 'dan'
...@@ -1144,10 +1110,9 @@ class Model { ...@@ -1144,10 +1110,9 @@ class Model {
* @return {Model} A reference to the model, with the scope(s) applied. Calling scope again on the returned model will clear the previous scope. * @return {Model} A reference to the model, with the scope(s) applied. Calling scope again on the returned model will clear the previous scope.
*/ */
static scope(option) { static scope(option) {
var self = class extends this {} const self = class extends this {};
, options let scope;
, scope let scopeName;
, scopeName;
Object.defineProperty(self, 'name', {value: this.name}); Object.defineProperty(self, 'name', {value: this.name});
self.$scope = {}; self.$scope = {};
...@@ -1157,8 +1122,8 @@ class Model { ...@@ -1157,8 +1122,8 @@ class Model {
return self; return self;
} }
options = _.flatten(arguments); const options = _.flatten(arguments);
options.forEach(function(option) { for (const option of options) {
scope = null; scope = null;
scopeName = null; scopeName = null;
...@@ -1190,7 +1155,7 @@ class Model { ...@@ -1190,7 +1155,7 @@ class Model {
} }
if (!!scope) { if (!!scope) {
_.assignWith(self.$scope, scope, function scopeCustomizer(objectValue, sourceValue, key) { _.assignWith(self.$scope, scope, (objectValue, sourceValue, key) => {
if (key === 'where') { if (key === 'where') {
return Array.isArray(sourceValue) ? sourceValue : _.assign(objectValue || {}, sourceValue); return Array.isArray(sourceValue) ? sourceValue : _.assign(objectValue || {}, sourceValue);
} else if ( (['attributes','include'].indexOf(key) >= 0) && Array.isArray(objectValue) && Array.isArray(sourceValue)) { } else if ( (['attributes','include'].indexOf(key) >= 0) && Array.isArray(objectValue) && Array.isArray(sourceValue)) {
...@@ -1202,7 +1167,7 @@ class Model { ...@@ -1202,7 +1167,7 @@ class Model {
} else { } else {
throw new Error('Invalid scope ' + scopeName + ' called.'); throw new Error('Invalid scope ' + scopeName + ' called.');
} }
}.bind(this)); }
return self; return self;
} }
...@@ -1320,8 +1285,8 @@ class Model { ...@@ -1320,8 +1285,8 @@ class Model {
if (arguments.length > 1) { if (arguments.length > 1) {
throw new Error('Please note that find* was refactored and uses only one options object from now on.'); throw new Error('Please note that find* was refactored and uses only one options object from now on.');
} }
var tableNames = {} const tableNames = {};
, originalOptions; let originalOptions;
tableNames[this.getTableName(options)] = true; tableNames[this.getTableName(options)] = true;
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
...@@ -1331,20 +1296,20 @@ class Model { ...@@ -1331,20 +1296,20 @@ class Model {
//set rejectOnEmpty option from model config //set rejectOnEmpty option from model config
options.rejectOnEmpty = options.rejectOnEmpty || this.options.rejectOnEmpty; options.rejectOnEmpty = options.rejectOnEmpty || this.options.rejectOnEmpty;
return Promise.bind(this).then(function() { return Promise.try(() => {
this._conformOptions(options, this); this._conformOptions(options, this);
this.$injectScope(options); this.$injectScope(options);
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeFind', options); return this.runHooks('beforeFind', options);
} }
}).then(function() { }).then(() => {
this._expandIncludeAll.call(this, options); this._expandIncludeAll(options);
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeFindAfterExpandIncludeAll', options); return this.runHooks('beforeFindAfterExpandIncludeAll', options);
} }
}).then(function() { }).then(() => {
if (options.include) { if (options.include) {
options.hasJoin = true; options.hasJoin = true;
...@@ -1371,15 +1336,15 @@ class Model { ...@@ -1371,15 +1336,15 @@ class Model {
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeFindAfterOptions', options); return this.runHooks('beforeFindAfterOptions', options);
} }
}).then(function() { }).then(() => {
originalOptions = Utils.cloneDeep(options); originalOptions = Utils.cloneDeep(options);
options.tableNames = Object.keys(tableNames); options.tableNames = Object.keys(tableNames);
return this.QueryInterface.select(this, this.getTableName(options), options); return this.QueryInterface.select(this, this.getTableName(options), options);
}).tap(function(results) { }).tap(results => {
if (options.hooks) { if (options.hooks) {
return this.runHooks('afterFind', results, options); return this.runHooks('afterFind', results, options);
} }
}).then(function (results) { }).then(results => {
//rejectOnEmpty mode //rejectOnEmpty mode
if (_.isEmpty(results) && options.rejectOnEmpty) { if (_.isEmpty(results) && options.rejectOnEmpty) {
...@@ -1399,16 +1364,16 @@ class Model { ...@@ -1399,16 +1364,16 @@ class Model {
static $findSeparate(results, options) { static $findSeparate(results, options) {
if (!options.include || options.raw || !results) return Promise.resolve(results); if (!options.include || options.raw || !results) return Promise.resolve(results);
var original = results; const original = results;
if (options.plain) results = [results]; if (options.plain) results = [results];
if (!results.length) return original; if (!results.length) return original;
return Promise.map(options.include, function (include) { return Promise.map(options.include, include => {
if (!include.separate) { if (!include.separate) {
return Model.$findSeparate( return Model.$findSeparate(
results.reduce(function (memo, result) { results.reduce((memo, result) => {
var associations = result.get(include.association.as); let associations = result.get(include.association.as);
// Might be an empty belongsTo relation // Might be an empty belongsTo relation
if (!associations) return memo; if (!associations) return memo;
...@@ -1430,8 +1395,8 @@ class Model { ...@@ -1430,8 +1395,8 @@ class Model {
{}, {},
_.omit(options, 'include', 'attributes', 'order', 'where', 'limit', 'plain'), _.omit(options, 'include', 'attributes', 'order', 'where', 'limit', 'plain'),
_.omit(include, 'parent', 'association', 'as') _.omit(include, 'parent', 'association', 'as')
)).then(function (map) { )).then(map => {
results.forEach(function (result) { for (const result of results) {
result.set( result.set(
include.association.as, include.association.as,
map[result.get(include.association.source.primaryKeyAttribute)], map[result.get(include.association.source.primaryKeyAttribute)],
...@@ -1439,7 +1404,7 @@ class Model { ...@@ -1439,7 +1404,7 @@ class Model {
raw: true raw: true
} }
); );
}); }
}); });
}).return(original); }).return(original);
} }
...@@ -1493,7 +1458,7 @@ class Model { ...@@ -1493,7 +1458,7 @@ class Model {
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
if (options.limit === undefined) { if (options.limit === undefined) {
var pkVal = options.where && options.where[this.primaryKeyAttribute]; const pkVal = options.where && options.where[this.primaryKeyAttribute];
// Don't add limit if querying directly on the pk // Don't add limit if querying directly on the pk
if (!options.where || !(Utils.isPrimitive(pkVal) || Buffer.isBuffer(pkVal))) { if (!options.where || !(Utils.isPrimitive(pkVal) || Buffer.isBuffer(pkVal))) {
...@@ -1535,9 +1500,9 @@ class Model { ...@@ -1535,9 +1500,9 @@ class Model {
this._validateIncludedElements(options); this._validateIncludedElements(options);
} }
var attrOptions = this.rawAttributes[attribute] const attrOptions = this.rawAttributes[attribute];
, field = attrOptions && attrOptions.field || attribute const field = attrOptions && attrOptions.field || attribute;
, aggregateColumn = this.sequelize.col(field); let aggregateColumn = this.sequelize.col(field);
if (options.distinct) { if (options.distinct) {
aggregateColumn = this.sequelize.fn('DISTINCT', aggregateColumn); aggregateColumn = this.sequelize.fn('DISTINCT', aggregateColumn);
...@@ -1583,16 +1548,16 @@ class Model { ...@@ -1583,16 +1548,16 @@ class Model {
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
_.defaults(options, { hooks: true }); _.defaults(options, { hooks: true });
var col = '*'; let col = '*';
return Promise.bind(this).then(function() { return Promise.try(() => {
this._conformOptions(options, this); this._conformOptions(options, this);
this.$injectScope(options); this.$injectScope(options);
if (options.hooks) { if (options.hooks) {
return this.runHooks('beforeCount', options); return this.runHooks('beforeCount', options);
} }
}).then(function() { }).then(() => {
if (options.include) { if (options.include) {
col = this.name + '.' + this.primaryKeyField; col = this.name + '.' + this.primaryKeyField;
this._expandIncludeAll(options); this._expandIncludeAll(options);
...@@ -1621,7 +1586,7 @@ class Model { ...@@ -1621,7 +1586,7 @@ class Model {
* where: ..., * where: ...,
* limit: 12, * limit: 12,
* offset: 12 * offset: 12
* }).then(function (result) { * }).then(result => {
* ... * ...
* }) * })
* ``` * ```
...@@ -1651,14 +1616,13 @@ class Model { ...@@ -1651,14 +1616,13 @@ class Model {
throw new Error('The argument passed to findAndCount must be an options object, use findById if you wish to pass a single primary key value'); throw new Error('The argument passed to findAndCount must be an options object, use findById if you wish to pass a single primary key value');
} }
var self = this
// no limit, offset, order, attributes for the options given to count() // no limit, offset, order, attributes for the options given to count()
, countOptions = _.omit(_.clone(options), ['offset', 'limit', 'order', 'attributes']); const countOptions = _.omit(_.clone(options), ['offset', 'limit', 'order', 'attributes']);
this._conformOptions(countOptions, this); this._conformOptions(countOptions, this);
if (countOptions.include) { if (countOptions.include) {
countOptions.include = _.cloneDeepWith(countOptions.include, function (element) { countOptions.include = _.cloneDeepWith(countOptions.include, element => {
if (element instanceof Model) return element; if (element instanceof Model) return element;
if (element instanceof Association) return element; if (element instanceof Association) return element;
return undefined; return undefined;
...@@ -1668,8 +1632,8 @@ class Model { ...@@ -1668,8 +1632,8 @@ class Model {
this._validateIncludedElements(countOptions); this._validateIncludedElements(countOptions);
var keepNeeded = function(includes) { const keepNeeded = includes => {
return includes.filter(function (include) { return includes.filter(include => {
if (include.include) include.include = keepNeeded(include.include); if (include.include) include.include = keepNeeded(include.include);
return include.required || include.hasIncludeRequired; return include.required || include.hasIncludeRequired;
...@@ -1683,19 +1647,17 @@ class Model { ...@@ -1683,19 +1647,17 @@ class Model {
} }
} }
return self.count(countOptions).then(function(count) { return this.count(countOptions).then(count => {
if (count === 0) { if (count === 0) {
return { return {
count: count || 0, count: count || 0,
rows: [] rows: []
}; };
} }
return self.findAll(options).then(function(results) { return this.findAll(options).then(results => ({
return {
count: count || 0, count: count || 0,
rows: (results && Array.isArray(results) ? results : []) rows: (results && Array.isArray(results) ? results : [])
}; }));
});
}); });
} }
...@@ -1760,9 +1722,7 @@ class Model { ...@@ -1760,9 +1722,7 @@ class Model {
}, options || {}); }, options || {});
if (options.attributes) { if (options.attributes) {
options.attributes = options.attributes.map(function(attribute) { options.attributes = options.attributes.map(attribute => Array.isArray(attribute) ? attribute[1] : attribute);
return Array.isArray(attribute) ? attribute[1] : attribute;
});
} }
if (!options.includeValidated) { if (!options.includeValidated) {
...@@ -1790,14 +1750,10 @@ class Model { ...@@ -1790,14 +1750,10 @@ class Model {
} }
if (options.attributes) { if (options.attributes) {
options.attributes = options.attributes.map(function(attribute) { options.attributes = options.attributes.map(attribute => Array.isArray(attribute) ? attribute[1] : attribute);
return Array.isArray(attribute) ? attribute[1] : attribute;
});
} }
return valueSets.map(function(values) { return valueSets.map(values => this.build(values, options));
return this.build(values, options);
}.bind(this));
} }
/** /**
...@@ -1854,17 +1810,16 @@ class Model { ...@@ -1854,17 +1810,16 @@ class Model {
); );
} }
var self = this let values;
, values;
return self.find(options).then(function(instance) { return this.find(options).then(instance => {
if (instance === null) { if (instance === null) {
values = Utils._.clone(options.defaults) || {}; values = Utils._.clone(options.defaults) || {};
if (Utils._.isPlainObject(options.where)) { if (Utils._.isPlainObject(options.where)) {
values = Utils._.defaults(values, options.where); values = Utils._.defaults(values, options.where);
} }
instance = self.build(values); instance = this.build(values);
return Promise.resolve([instance, true]); return Promise.resolve([instance, true]);
} }
...@@ -1899,26 +1854,23 @@ class Model { ...@@ -1899,26 +1854,23 @@ class Model {
options = _.assign({}, options); options = _.assign({}, options);
if (options.transaction === undefined && this.sequelize.constructor.cls) { if (options.transaction === undefined && this.sequelize.constructor.cls) {
var t = this.sequelize.constructor.cls.get('transaction'); const t = this.sequelize.constructor.cls.get('transaction');
if (t) { if (t) {
options.transaction = t; options.transaction = t;
} }
} }
var self = this const internalTransaction = !options.transaction;
, internalTransaction = !options.transaction let values;
, values let transaction;
, transaction;
// Create a transaction or a savepoint, depending on whether a transaction was passed in // Create a transaction or a savepoint, depending on whether a transaction was passed in
return self.sequelize.transaction(options).bind({}).then(function (t) { return this.sequelize.transaction(options).then(t => {
transaction = t; transaction = t;
options.transaction = t; options.transaction = t;
return self.findOne(_.defaults({ return this.findOne(_.defaults({transaction}, options));
transaction: transaction }).then(instance => {
}, options));
}).then(function(instance) {
if (instance !== null) { if (instance !== null) {
return [instance, false]; return [instance, false];
} }
...@@ -1930,16 +1882,16 @@ class Model { ...@@ -1930,16 +1882,16 @@ class Model {
options.exception = true; options.exception = true;
return self.create(values, options).bind(this).then(function(instance) { return this.create(values, options).then(instance => {
if (instance.get(self.primaryKeyAttribute, { raw: true }) === null) { if (instance.get(this.primaryKeyAttribute, { raw: true }) === null) {
// If the query returned an empty result for the primary key, we know that this was actually a unique constraint violation // If the query returned an empty result for the primary key, we know that this was actually a unique constraint violation
throw new self.sequelize.UniqueConstraintError(); throw new this.sequelize.UniqueConstraintError();
} }
return [instance, true]; return [instance, true];
}).catch(self.sequelize.UniqueConstraintError, function (err) { }).catch(this.sequelize.UniqueConstraintError, err => {
let whereFields = Object.keys(options.where).map(name => self.rawAttributes[name].field || name) const whereFields = Object.keys(options.where).map(name => this.rawAttributes[name].field || name);
, defaultFields = options.defaults && Object.keys(options.defaults).map(name => self.rawAttributes[name].field || name); const defaultFields = options.defaults && Object.keys(options.defaults).map(name => this.rawAttributes[name].field || name);
if (defaultFields) { if (defaultFields) {
if (!_.intersection(Object.keys(err.fields), whereFields).length && _.intersection(Object.keys(err.fields), defaultFields).length) { if (!_.intersection(Object.keys(err.fields), whereFields).length && _.intersection(Object.keys(err.fields), defaultFields).length) {
...@@ -1949,24 +1901,24 @@ class Model { ...@@ -1949,24 +1901,24 @@ class Model {
if (_.intersection(Object.keys(err.fields), whereFields).length) { if (_.intersection(Object.keys(err.fields), whereFields).length) {
_.each(err.fields, (value, key) => { _.each(err.fields, (value, key) => {
let name = self.fieldRawAttributesMap[key].fieldName; const name = this.fieldRawAttributesMap[key].fieldName;
if (value.toString() !== options.where[name].toString()) { if (value.toString() !== options.where[name].toString()) {
throw new Error(`${self.name}#findOrCreate: value used for ${name} was not equal for both the find and the create calls, '${options.where[name]}' vs '${value}'`); throw new Error(`${this.name}#findOrCreate: value used for ${name} was not equal for both the find and the create calls, '${options.where[name]}' vs '${value}'`);
} }
}); });
} }
// Someone must have created a matching instance inside the same transaction since we last did a find. Let's find it! // Someone must have created a matching instance inside the same transaction since we last did a find. Let's find it!
return self.findOne(_.defaults({ return this.findOne(_.defaults({
transaction: internalTransaction ? null : transaction transaction: internalTransaction ? null : transaction
}, options)).then(function(instance) { }, options)).then(instance => {
// Sanity check, ideally we caught this at the defaultFeilds/err.fields check // Sanity check, ideally we caught this at the defaultFeilds/err.fields check
// But if we didn't and instance is null, we will throw // But if we didn't and instance is null, we will throw
if (instance === null) throw err; if (instance === null) throw err;
return [instance, false]; return [instance, false];
}); });
}); });
}).finally(function () { }).finally(() => {
if (internalTransaction && transaction) { if (internalTransaction && transaction) {
// If we created a transaction internally (and not just a savepoint), we should clean it up // If we created a transaction internally (and not just a savepoint), we should clean it up
return transaction.commit(); return transaction.commit();
...@@ -1991,22 +1943,18 @@ class Model { ...@@ -1991,22 +1943,18 @@ class Model {
); );
} }
var values = Utils._.clone(options.defaults) || {}; let values = Utils._.clone(options.defaults) || {};
if (Utils._.isPlainObject(options.where)) { if (Utils._.isPlainObject(options.where)) {
values = _.defaults(values, options.where); values = _.defaults(values, options.where);
} }
return this.findOne(options).bind(this).then(function (result) { return this.findOne(options).then(result => {
if (result) return [result, false]; if (result) return [result, false];
return this.create(values, options).bind(this).then(function (result) { return this.create(values, options)
return [result, true]; .then(result => [result, true])
}).catch(this.sequelize.UniqueConstraintError, function (err) { .catch(this.sequelize.UniqueConstraintError, err => this.findOne(options).then(result => [result, false]));
return this.findOne(options).then(function (result) {
return [result, false];
});
});
}); });
} }
...@@ -2040,17 +1988,17 @@ class Model { ...@@ -2040,17 +1988,17 @@ class Model {
options.fields = Object.keys(this.attributes); options.fields = Object.keys(this.attributes);
} }
var createdAtAttr = this._timestampAttributes.createdAt const createdAtAttr = this._timestampAttributes.createdAt
, updatedAtAttr = this._timestampAttributes.updatedAt , updatedAtAttr = this._timestampAttributes.updatedAt
, hadPrimary = this.primaryKeyField in values || this.primaryKeyAttribute in values , hadPrimary = this.primaryKeyField in values || this.primaryKeyAttribute in values
, instance = this.build(values); , instance = this.build(values);
return instance.validate(options).bind(this).then(function () { return instance.validate(options).then(() => {
// Map field names // Map field names
var updatedDataValues = _.pick(instance.dataValues, Object.keys(instance._changed)) const updatedDataValues = _.pick(instance.dataValues, Object.keys(instance._changed));
, insertValues = Utils.mapValueFieldNames(instance.dataValues, options.fields, this) const insertValues = Utils.mapValueFieldNames(instance.dataValues, options.fields, this);
, updateValues = Utils.mapValueFieldNames(updatedDataValues, options.fields, this) const updateValues = Utils.mapValueFieldNames(updatedDataValues, options.fields, this);
, now = Utils.now(this.sequelize.options.dialect); const now = Utils.now(this.sequelize.options.dialect);
// Attach createdAt // Attach createdAt
if (createdAtAttr && !updateValues[createdAtAttr]) { if (createdAtAttr && !updateValues[createdAtAttr]) {
...@@ -2110,7 +2058,7 @@ class Model { ...@@ -2110,7 +2058,7 @@ class Model {
options.fields = options.fields || Object.keys(this.tableAttributes); options.fields = options.fields || Object.keys(this.tableAttributes);
var dialect = this.sequelize.options.dialect; const dialect = this.sequelize.options.dialect;
if (options.ignoreDuplicates && ['postgres', 'mssql'].indexOf(dialect) !== -1) { if (options.ignoreDuplicates && ['postgres', 'mssql'].indexOf(dialect) !== -1) {
return Promise.reject(new Error(dialect + ' does not support the \'ignoreDuplicates\' option.')); return Promise.reject(new Error(dialect + ' does not support the \'ignoreDuplicates\' option.'));
} }
...@@ -2120,7 +2068,7 @@ class Model { ...@@ -2120,7 +2068,7 @@ class Model {
if (options.updateOnDuplicate) { if (options.updateOnDuplicate) {
// By default, all attributes except 'createdAt' can be updated // By default, all attributes except 'createdAt' can be updated
var updatableFields = Utils._.pull(Object.keys(this.tableAttributes), 'createdAt'); let updatableFields = Utils._.pull(Object.keys(this.tableAttributes), 'createdAt');
if (Utils._.isArray(options.updateOnDuplicate) && !Utils._.isEmpty(options.updateOnDuplicate)) { if (Utils._.isArray(options.updateOnDuplicate) && !Utils._.isEmpty(options.updateOnDuplicate)) {
updatableFields = Utils._.intersection(updatableFields, options.updateOnDuplicate); updatableFields = Utils._.intersection(updatableFields, options.updateOnDuplicate);
} }
...@@ -2129,41 +2077,38 @@ class Model { ...@@ -2129,41 +2077,38 @@ class Model {
options.model = this; options.model = this;
var self = this const createdAtAttr = this._timestampAttributes.createdAt;
, createdAtAttr = this._timestampAttributes.createdAt const updatedAtAttr = this._timestampAttributes.updatedAt;
, updatedAtAttr = this._timestampAttributes.updatedAt const now = Utils.now(this.modelManager.sequelize.options.dialect);
, now = Utils.now(self.modelManager.sequelize.options.dialect);
var instances = records.map(function(values) { let instances = records.map(values => this.build(values, {isNewRecord: true}));
return self.build(values, {isNewRecord: true});
});
return Promise.try(function() { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('beforeBulkCreate', instances, options); return this.runHooks('beforeBulkCreate', instances, options);
} }
}).then(function() { }).then(() => {
// Validate // Validate
if (options.validate) { if (options.validate) {
var errors = new Promise.AggregateError() const errors = new Promise.AggregateError()
, validateOptions = _.clone(options); , validateOptions = _.clone(options);
validateOptions.hooks = options.individualHooks; validateOptions.hooks = options.individualHooks;
return Promise.map(instances, function(instance) { return Promise.map(instances, instance =>
return instance.validate(validateOptions).catch(function (err) { instance.validate(validateOptions).catch(err => {
errors.push({record: instance, errors: err}); errors.push({record: instance, errors: err});
}); })
}).then(function() { ).then(() => {
delete options.skip; delete options.skip;
if (errors.length) { if (errors.length) {
throw errors; throw errors;
} }
}); });
} }
}).then(function() { }).then(() => {
instances.forEach(function(instance) { for (const instance of instances) {
var values = Utils.mapValueFieldNames(instance.dataValues, options.fields, self); const values = Utils.mapValueFieldNames(instance.dataValues, options.fields, this);
// set createdAt/updatedAt attributes // set createdAt/updatedAt attributes
if (createdAtAttr && !values[createdAtAttr]) { if (createdAtAttr && !values[createdAtAttr]) {
...@@ -2174,12 +2119,12 @@ class Model { ...@@ -2174,12 +2119,12 @@ class Model {
} }
instance.dataValues = values; instance.dataValues = values;
}); }
if (options.individualHooks) { if (options.individualHooks) {
// Create each instance individually // Create each instance individually
return Promise.map(instances, function(instance) { return Promise.map(instances, instance => {
var individualOptions = Utils._.clone(options); const individualOptions = Utils._.clone(options);
delete individualOptions.fields; delete individualOptions.fields;
delete individualOptions.individualHooks; delete individualOptions.individualHooks;
delete individualOptions.ignoreDuplicates; delete individualOptions.ignoreDuplicates;
...@@ -2187,43 +2132,41 @@ class Model { ...@@ -2187,43 +2132,41 @@ class Model {
individualOptions.hooks = true; individualOptions.hooks = true;
return instance.save(individualOptions); return instance.save(individualOptions);
}).then(function(_instances) { }).then(_instances => {
instances = _instances; instances = _instances;
}); });
} else { } else {
// Create all in one query // Create all in one query
// Recreate records from instances to represent any changes made in hooks or validation // Recreate records from instances to represent any changes made in hooks or validation
records = instances.map(function(instance) { records = instances.map(instance => {
return Utils._.omit(instance.dataValues, self._virtualAttributes); return Utils._.omit(instance.dataValues, this._virtualAttributes);
}); });
// Map attributes for serial identification // Map attributes for serial identification
var attributes = {}; const attributes = {};
for (var attr in self.tableAttributes) { for (const attr in this.tableAttributes) {
attributes[attr] = self.rawAttributes[attr]; attributes[attr] = this.rawAttributes[attr];
if (self.rawAttributes[attr].field) { if (this.rawAttributes[attr].field) {
attributes[self.rawAttributes[attr].field] = self.rawAttributes[attr]; attributes[this.rawAttributes[attr].field] = this.rawAttributes[attr];
} }
} }
return self.QueryInterface.bulkInsert(self.getTableName(options), records, options, attributes).then(function (results) { return this.QueryInterface.bulkInsert(this.getTableName(options), records, options, attributes).then(results => {
if (Array.isArray(results)) { if (Array.isArray(results)) {
results.forEach(function (result, i) { results.forEach((result, i) => {
instances[i].set(self.primaryKeyAttribute, result[self.rawAttributes[self.primaryKeyAttribute].field], {raw: true}); instances[i].set(this.primaryKeyAttribute, result[this.rawAttributes[this.primaryKeyAttribute].field], {raw: true});
instances[i].isNewRecord = false; instances[i].isNewRecord = false;
}); });
} }
return results; return results;
}); });
} }
}).then(function() { }).then(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('afterBulkCreate', instances, options); return this.runHooks('afterBulkCreate', instances, options);
} }
}).then(function() { }).then(() => instances);
return instances;
});
} }
/** /**
...@@ -2264,8 +2207,7 @@ class Model { ...@@ -2264,8 +2207,7 @@ class Model {
* @return {Promise<Integer>} The number of destroyed rows * @return {Promise<Integer>} The number of destroyed rows
*/ */
static destroy(options) { static destroy(options) {
var self = this let instances;
, instances;
if (!options || !(options.where || options.truncate)) { if (!options || !(options.where || options.truncate)) {
throw new Error('Missing where or truncate attribute in the options parameter of model.destroy.'); throw new Error('Missing where or truncate attribute in the options parameter of model.destroy.');
...@@ -2287,53 +2229,47 @@ class Model { ...@@ -2287,53 +2229,47 @@ class Model {
this.$injectScope(options); this.$injectScope(options);
Utils.mapOptionFieldNames(options, this); Utils.mapOptionFieldNames(options, this);
options.model = self; options.model = this;
return Promise.try(function() { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('beforeBulkDestroy', options); return this.runHooks('beforeBulkDestroy', options);
} }
}).then(function() { }).then(() => {
// Get daos and run beforeDestroy hook on each record individually // Get daos and run beforeDestroy hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return self.findAll({where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark}).map(function(instance) { return this.findAll({where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark})
return self.runHooks('beforeDestroy', instance, options).then(function() { .map(instance => this.runHooks('beforeDestroy', instance, options).then(() => instance))
return instance; .then(_instances => {
});
}).then(function(_instances) {
instances = _instances; instances = _instances;
}); });
} }
}).then(function() { }).then(() => {
// Run delete query (or update if paranoid) // Run delete query (or update if paranoid)
if (self._timestampAttributes.deletedAt && !options.force) { if (this._timestampAttributes.deletedAt && !options.force) {
var attrValueHash = {} const attrValueHash = {}
, deletedAtAttribute = self.rawAttributes[self._timestampAttributes.deletedAt] , deletedAtAttribute = this.rawAttributes[this._timestampAttributes.deletedAt]
, field = self.rawAttributes[self._timestampAttributes.deletedAt].field , field = this.rawAttributes[this._timestampAttributes.deletedAt].field
, where = {}; , where = {};
where[field] = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null; where[field] = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null;
attrValueHash[field] = Utils.now(self.modelManager.sequelize.options.dialect); attrValueHash[field] = Utils.now(this.modelManager.sequelize.options.dialect);
return self.QueryInterface.bulkUpdate(self.getTableName(options), attrValueHash, _.defaults(where, options.where), options, self.rawAttributes); return this.QueryInterface.bulkUpdate(this.getTableName(options), attrValueHash, _.defaults(where, options.where), options, this.rawAttributes);
} else { } else {
return self.QueryInterface.bulkDelete(self.getTableName(options), options.where, options, self); return this.QueryInterface.bulkDelete(this.getTableName(options), options.where, options, this);
} }
}).tap(function() { }).tap(() => {
// Run afterDestroy hook on each record individually // Run afterDestroy hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return Promise.map(instances, function(instance) { return Promise.map(instances, instance => this.runHooks('afterDestroy', instance, options));
return self.runHooks('afterDestroy', instance, options);
});
} }
}).tap(function() { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('afterBulkDestroy', options); return this.runHooks('afterBulkDestroy', options);
} }
}).then(function(affectedRows) {
return affectedRows;
}); });
} }
...@@ -2362,51 +2298,44 @@ class Model { ...@@ -2362,51 +2298,44 @@ class Model {
options.type = QueryTypes.RAW; options.type = QueryTypes.RAW;
options.model = this; options.model = this;
var self = this let instances;
, instances;
Utils.mapOptionFieldNames(options, this); Utils.mapOptionFieldNames(options, this);
return Promise.try(function() { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('beforeBulkRestore', options); return this.runHooks('beforeBulkRestore', options);
} }
}).then(function() { }).then(() => {
// Get daos and run beforeRestore hook on each record individually // Get daos and run beforeRestore hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return self.findAll({where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark, paranoid: false}).map(function(instance) { return this.findAll({where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark, paranoid: false})
return self.runHooks('beforeRestore', instance, options).then(function() { .map(instance => this.runHooks('beforeRestore', instance, options).then(() => instance))
return instance; .then((_instances) => {
});
}).then(function(_instances) {
instances = _instances; instances = _instances;
}); });
} }
}).then(function() { }).then(() => {
// Run undelete query // Run undelete query
var attrValueHash = {} const attrValueHash = {};
, deletedAtCol = self._timestampAttributes.deletedAt const deletedAtCol = this._timestampAttributes.deletedAt;
, deletedAtAttribute = self.rawAttributes[deletedAtCol] const deletedAtAttribute = this.rawAttributes[deletedAtCol];
, deletedAtDefaultValue = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null; const deletedAtDefaultValue = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null;
attrValueHash[deletedAtCol] = deletedAtDefaultValue; attrValueHash[deletedAtCol] = deletedAtDefaultValue;
options.omitNull = false; options.omitNull = false;
return self.QueryInterface.bulkUpdate(self.getTableName(options), attrValueHash, options.where, options, self._timestampAttributes.deletedAt); return this.QueryInterface.bulkUpdate(this.getTableName(options), attrValueHash, options.where, options, this._timestampAttributes.deletedAt);
}).tap(function() { }).tap(() => {
// Run afterDestroy hook on each record individually // Run afterDestroy hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return Promise.map(instances, function(instance) { return Promise.map(instances, instance => this.runHooks('afterRestore', instance, options));
return self.runHooks('afterRestore', instance, options);
});
} }
}).tap(function() { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.runHooks('afterBulkRestore', options); return this.runHooks('afterBulkRestore', options);
} }
}).then(function(affectedRows) {
return affectedRows;
}); });
} }
...@@ -2432,7 +2361,6 @@ class Model { ...@@ -2432,7 +2361,6 @@ class Model {
* @return {Promise<Array<affectedCount,affectedRows>>} * @return {Promise<Array<affectedCount,affectedRows>>}
*/ */
static update(values, options) { static update(values, options) {
var self = this;
if (!options || !options.where) { if (!options || !options.where) {
throw new Error('Missing where attribute in the options parameter passed to update.'); throw new Error('Missing where attribute in the options parameter passed to update.');
...@@ -2461,13 +2389,13 @@ class Model { ...@@ -2461,13 +2389,13 @@ class Model {
// Remove values that are not in the options.fields // Remove values that are not in the options.fields
if (options.fields && options.fields instanceof Array) { if (options.fields && options.fields instanceof Array) {
Object.keys(values).forEach(function(key) { for (const key of Object.keys(values)) {
if (options.fields.indexOf(key) < 0) { if (options.fields.indexOf(key) < 0) {
delete values[key]; delete values[key];
} }
}); }
} else { } else {
var updatedAtAttr = this._timestampAttributes.updatedAt; const updatedAtAttr = this._timestampAttributes.updatedAt;
options.fields = _.intersection(Object.keys(values), Object.keys(this.tableAttributes)); options.fields = _.intersection(Object.keys(values), Object.keys(this.tableAttributes));
if (updatedAtAttr && options.fields.indexOf(updatedAtAttr) === -1) { if (updatedAtAttr && options.fields.indexOf(updatedAtAttr) === -1) {
options.fields.push(updatedAtAttr); options.fields.push(updatedAtAttr);
...@@ -2480,14 +2408,14 @@ class Model { ...@@ -2480,14 +2408,14 @@ class Model {
options.model = this; options.model = this;
var instances let instances;
, valuesUse; let valuesUse;
return Promise.try(function() { return Promise.try(() => {
// Validate // Validate
if (options.validate) { if (options.validate) {
var build = self.build(values); const build = this.build(values);
build.set(self._timestampAttributes.updatedAt, values[self._timestampAttributes.updatedAt], { raw: true }); build.set(this._timestampAttributes.updatedAt, values[this._timestampAttributes.updatedAt], { raw: true });
if (options.sideEffects) { if (options.sideEffects) {
values = Utils._.assign(values, Utils._.pick(build.get(), build.changed())); values = Utils._.assign(values, Utils._.pick(build.get(), build.changed()));
...@@ -2495,8 +2423,8 @@ class Model { ...@@ -2495,8 +2423,8 @@ class Model {
} }
// We want to skip validations for all other fields // We want to skip validations for all other fields
options.skip = Utils._.difference(Object.keys(self.attributes), Object.keys(values)); options.skip = Utils._.difference(Object.keys(this.attributes), Object.keys(values));
return build.validate(options).then(function(attributes) { return build.validate(options).then(attributes => {
options.skip = undefined; options.skip = undefined;
if (attributes && attributes.dataValues) { if (attributes && attributes.dataValues) {
values = Utils._.pick(attributes.dataValues, Object.keys(values)); values = Utils._.pick(attributes.dataValues, Object.keys(values));
...@@ -2504,22 +2432,22 @@ class Model { ...@@ -2504,22 +2432,22 @@ class Model {
}); });
} }
return null; return null;
}).then(function() { }).then(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
options.attributes = values; options.attributes = values;
return self.runHooks('beforeBulkUpdate', options).then(function() { return this.runHooks('beforeBulkUpdate', options).then(() => {
values = options.attributes; values = options.attributes;
delete options.attributes; delete options.attributes;
}); });
} }
return null; return null;
}).then(function() { }).then(() => {
valuesUse = values; valuesUse = values;
// Get instances and run beforeUpdate hook on each record individually // Get instances and run beforeUpdate hook on each record individually
if (options.individualHooks) { if (options.individualHooks) {
return self.findAll({where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark}).then(function(_instances) { return this.findAll({where: options.where, transaction: options.transaction, logging: options.logging, benchmark: options.benchmark}).then(_instances => {
instances = _instances; instances = _instances;
if (!instances.length) { if (!instances.length) {
return []; return [];
...@@ -2527,24 +2455,24 @@ class Model { ...@@ -2527,24 +2455,24 @@ class Model {
// Run beforeUpdate hooks on each record and check whether beforeUpdate hook changes values uniformly // Run beforeUpdate hooks on each record and check whether beforeUpdate hook changes values uniformly
// i.e. whether they change values for each record in the same way // i.e. whether they change values for each record in the same way
var changedValues let changedValues;
, different = false; let different = false;
return Promise.map(instances, function(instance) { return Promise.map(instances, instance => {
// Record updates in instances dataValues // Record updates in instances dataValues
Utils._.extend(instance.dataValues, values); Utils._.extend(instance.dataValues, values);
// Set the changed fields on the instance // Set the changed fields on the instance
Utils._.forIn(valuesUse, function(newValue, attr) { Utils._.forIn(valuesUse, (newValue, attr) => {
if (newValue !== instance._previousDataValues[attr]) { if (newValue !== instance._previousDataValues[attr]) {
instance.setDataValue(attr, newValue); instance.setDataValue(attr, newValue);
} }
}); });
// Run beforeUpdate hook // Run beforeUpdate hook
return self.runHooks('beforeUpdate', instance, options).then(function() { return this.runHooks('beforeUpdate', instance, options).then(() => {
if (!different) { if (!different) {
var thisChangedValues = {}; const thisChangedValues = {};
Utils._.forIn(instance.dataValues, function(newValue, attr) { Utils._.forIn(instance.dataValues, (newValue, attr) => {
if (newValue !== instance._previousDataValues[attr]) { if (newValue !== instance._previousDataValues[attr]) {
thisChangedValues[attr] = newValue; thisChangedValues[attr] = newValue;
} }
...@@ -2559,11 +2487,11 @@ class Model { ...@@ -2559,11 +2487,11 @@ class Model {
return instance; return instance;
}); });
}).then(function(_instances) { }).then(_instances => {
instances = _instances; instances = _instances;
if (!different) { if (!different) {
var keys = Object.keys(changedValues); const keys = Object.keys(changedValues);
// Hooks do not change values or change them uniformly // Hooks do not change values or change them uniformly
if (keys.length) { if (keys.length) {
// Hooks change values - record changes in valuesUse so they are executed // Hooks change values - record changes in valuesUse so they are executed
...@@ -2574,32 +2502,32 @@ class Model { ...@@ -2574,32 +2502,32 @@ class Model {
} else { } else {
// Hooks change values in a different way for each record // Hooks change values in a different way for each record
// Do not run original query but save each record individually // Do not run original query but save each record individually
return Promise.map(instances, function(instance) { return Promise.map(instances, instance => {
var individualOptions = Utils._.clone(options); const individualOptions = Utils._.clone(options);
delete individualOptions.individualHooks; delete individualOptions.individualHooks;
individualOptions.hooks = false; individualOptions.hooks = false;
individualOptions.validate = false; individualOptions.validate = false;
return instance.save(individualOptions); return instance.save(individualOptions);
}).tap(function(_instances) { }).tap(_instances => {
instances = _instances; instances = _instances;
}); });
} }
}); });
}); });
} }
}).then(function(results) { }).then(results => {
if (results) { if (results) {
// Update already done row-by-row - exit // Update already done row-by-row - exit
return [results.length, results]; return [results.length, results];
} }
valuesUse = Utils.mapValueFieldNames(valuesUse, options.fields, self); valuesUse = Utils.mapValueFieldNames(valuesUse, options.fields, this);
options = Utils.mapOptionFieldNames(options, self); options = Utils.mapOptionFieldNames(options, this);
options.hasTrigger = self.options ? self.options.hasTrigger : false; options.hasTrigger = this.options ? this.options.hasTrigger : false;
// Run query to update all rows // Run query to update all rows
return self.QueryInterface.bulkUpdate(self.getTableName(options), valuesUse, options.where, options, self.tableAttributes).then(function(affectedRows) { return this.QueryInterface.bulkUpdate(this.getTableName(options), valuesUse, options.where, options, this.tableAttributes).then(affectedRows => {
if (options.returning) { if (options.returning) {
instances = affectedRows; instances = affectedRows;
return [affectedRows.length, affectedRows]; return [affectedRows.length, affectedRows];
...@@ -2607,25 +2535,22 @@ class Model { ...@@ -2607,25 +2535,22 @@ class Model {
return [affectedRows]; return [affectedRows];
}); });
}).tap(function(result) { }).tap(result => {
if (options.individualHooks) { if (options.individualHooks) {
return Promise.map(instances, function(instance) { return Promise.map(instances, instance => {
return self.runHooks('afterUpdate', instance, options); return this.runHooks('afterUpdate', instance, options);
}).then(function() { }).then(() => {
result[1] = instances; result[1] = instances;
}); });
} }
}).tap(function() { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
options.attributes = values; options.attributes = values;
return self.runHooks('afterBulkUpdate', options).then(function() { return this.runHooks('afterBulkUpdate', options).then(() => {
delete options.attributes; delete options.attributes;
}); });
} }
}).then(function(result) {
// Return result in form [affectedRows, instances] (instances missed off if options.individualHooks != true)
return result;
}); });
} }
...@@ -2647,10 +2572,10 @@ class Model { ...@@ -2647,10 +2572,10 @@ class Model {
static $expandAttributes(options) { static $expandAttributes(options) {
if (_.isPlainObject(options.attributes)) { if (_.isPlainObject(options.attributes)) {
var attributes = Object.keys(this.rawAttributes); let attributes = Object.keys(this.rawAttributes);
if (options.attributes.exclude) { if (options.attributes.exclude) {
attributes = attributes.filter(function (elem) { attributes = attributes.filter(elem => {
return options.attributes.exclude.indexOf(elem) === -1; return options.attributes.exclude.indexOf(elem) === -1;
}); });
} }
...@@ -2664,10 +2589,9 @@ class Model { ...@@ -2664,10 +2589,9 @@ class Model {
// Inject $scope into options. Includes should have been conformed (conformOptions) before calling this // Inject $scope into options. Includes should have been conformed (conformOptions) before calling this
static $injectScope(options) { static $injectScope(options) {
var self = this; const scope = Utils.cloneDeep(this.$scope);
var scope = Utils.cloneDeep(this.$scope);
var filteredScope = _.omit(scope, 'include'); // Includes need special treatment const filteredScope = _.omit(scope, 'include'); // Includes need special treatment
_.defaults(options, filteredScope); _.defaults(options, filteredScope);
_.defaults(options.where, filteredScope.where); _.defaults(options.where, filteredScope.where);
...@@ -2677,21 +2601,21 @@ class Model { ...@@ -2677,21 +2601,21 @@ class Model {
// Reverse so we consider the latest include first. // Reverse so we consider the latest include first.
// This is used if several scopes specify the same include - the last scope should take precedence // This is used if several scopes specify the same include - the last scope should take precedence
scope.include.reverse().forEach(function (scopeInclude) { for (const scopeInclude of scope.include.reverse()) {
if (scopeInclude.all || !options.include.some(function matchesModelAndAlias(item) { if (scopeInclude.all || !options.include.some(item => {
var isSameModel = item.model && item.model.name === scopeInclude.model.name; const isSameModel = item.model && item.model.name === scopeInclude.model.name;
if (!isSameModel || !item.as) return isSameModel; if (!isSameModel || !item.as) return isSameModel;
if (scopeInclude.as) { if (scopeInclude.as) {
return item.as === scopeInclude.as; return item.as === scopeInclude.as;
} else { } else {
var association = scopeInclude.association || self.getAssociation(scopeInclude.model, scopeInclude.as); const association = scopeInclude.association || this.getAssociation(scopeInclude.model, scopeInclude.as);
return association ? item.as === association.as : false; return association ? item.as === association.as : false;
} }
})) { })) {
options.include.push(scopeInclude); options.include.push(scopeInclude);
} }
}); }
} }
} }
...@@ -2725,8 +2649,8 @@ class Model { ...@@ -2725,8 +2649,8 @@ class Model {
} }
_initValues(values, options) { _initValues(values, options) {
var defaults let defaults;
, key; let key;
values = values && _.clone(values) || {}; values = values && _.clone(values) || {};
...@@ -2734,8 +2658,8 @@ class Model { ...@@ -2734,8 +2658,8 @@ class Model {
defaults = {}; defaults = {};
if (this.constructor._hasDefaultValues) { if (this.constructor._hasDefaultValues) {
defaults = _.mapValues(this.constructor._defaultValues, function(valueFn) { defaults = _.mapValues(this.constructor._defaultValues, valueFn => {
var value = valueFn(); const value = valueFn();
return (value && value._isSequelizeMethod) ? value : _.cloneDeep(value); return (value && value._isSequelizeMethod) ? value : _.cloneDeep(value);
}); });
} }
...@@ -2792,12 +2716,10 @@ class Model { ...@@ -2792,12 +2716,10 @@ class Model {
* @return {Object} * @return {Object}
*/ */
where() { where() {
var where; const where = this.constructor.primaryKeyAttributes.reduce((result, attribute) => {
where = this.constructor.primaryKeyAttributes.reduce(function (result, attribute) {
result[attribute] = this.get(attribute, {raw: true}); result[attribute] = this.get(attribute, {raw: true});
return result; return result;
}.bind(this), {}); }, {});
if (_.size(where) === 0) { if (_.size(where) === 0) {
return this.$modelOptions.whereCollection; return this.$modelOptions.whereCollection;
...@@ -2826,7 +2748,7 @@ class Model { ...@@ -2826,7 +2748,7 @@ class Model {
* @param {any} value * @param {any} value
*/ */
setDataValue(key, value) { setDataValue(key, value) {
var originalValue = this._previousDataValues[key]; const originalValue = this._previousDataValues[key];
if (!Utils.isPrimitive(value) || value !== originalValue) { if (!Utils.isPrimitive(value) || value !== originalValue) {
this.changed(key, true); this.changed(key, true);
} }
...@@ -2859,9 +2781,7 @@ class Model { ...@@ -2859,9 +2781,7 @@ class Model {
} }
if (options.plain && this.$options.include && this.$options.includeNames.indexOf(key) !== -1) { if (options.plain && this.$options.include && this.$options.includeNames.indexOf(key) !== -1) {
if (Array.isArray(this.dataValues[key])) { if (Array.isArray(this.dataValues[key])) {
return this.dataValues[key].map(function (instance) { return this.dataValues[key].map(instance => instance.get({plain: options.plain}));
return instance.get({plain: options.plain});
});
} else if (this.dataValues[key] instanceof Model) { } else if (this.dataValues[key] instanceof Model) {
return this.dataValues[key].get({plain: options.plain}); return this.dataValues[key].get({plain: options.plain});
} else { } else {
...@@ -2872,8 +2792,8 @@ class Model { ...@@ -2872,8 +2792,8 @@ class Model {
} }
if (this._hasCustomGetters || (options.plain && this.$options.include) || options.clone) { if (this._hasCustomGetters || (options.plain && this.$options.include) || options.clone) {
var values = {} const values = {};
, _key; let _key;
if (this._hasCustomGetters) { if (this._hasCustomGetters) {
for (_key in this._customGetters) { for (_key in this._customGetters) {
...@@ -2918,11 +2838,8 @@ class Model { ...@@ -2918,11 +2838,8 @@ class Model {
* @alias setAttributes * @alias setAttributes
*/ */
set(key, value, options) { // testhint options:none set(key, value, options) { // testhint options:none
var values let values;
, originalValue let originalValue;
, keys
, i
, length;
if (typeof key === 'object' && key !== null) { if (typeof key === 'object' && key !== null) {
values = key; values = key;
...@@ -2945,7 +2862,7 @@ class Model { ...@@ -2945,7 +2862,7 @@ class Model {
// Loop and call set // Loop and call set
if (options.attributes) { if (options.attributes) {
keys = options.attributes; let keys = options.attributes;
if (this.constructor._hasVirtualAttributes) { if (this.constructor._hasVirtualAttributes) {
keys = keys.concat(this.constructor._virtualAttributes); keys = keys.concat(this.constructor._virtualAttributes);
} }
...@@ -2954,13 +2871,13 @@ class Model { ...@@ -2954,13 +2871,13 @@ class Model {
keys = keys.concat(this.$options.includeNames); keys = keys.concat(this.$options.includeNames);
} }
for (i = 0, length = keys.length; i < length; i++) { for (let i = 0, length = keys.length; i < length; i++) {
if (values[keys[i]] !== undefined) { if (values[keys[i]] !== undefined) {
this.set(keys[i], values[keys[i]], options); this.set(keys[i], values[keys[i]], options);
} }
} }
} else { } else {
for (key in values) { for (const key in values) {
this.set(key, values[key], options); this.set(key, values[key], options);
} }
} }
...@@ -2993,7 +2910,7 @@ class Model { ...@@ -2993,7 +2910,7 @@ class Model {
// If attribute is not in model definition, return // If attribute is not in model definition, return
if (!this._isAttribute(key)) { if (!this._isAttribute(key)) {
if (key.indexOf('.') > -1 && this.constructor._isJsonAttribute(key.split('.')[0])) { if (key.indexOf('.') > -1 && this.constructor._isJsonAttribute(key.split('.')[0])) {
var previousDottieValue = Dottie.get(this.dataValues, key); const previousDottieValue = Dottie.get(this.dataValues, key);
if (!_.isEqual(previousDottieValue, value)) { if (!_.isEqual(previousDottieValue, value)) {
Dottie.set(this.dataValues, key, value); Dottie.set(this.dataValues, key, value);
this.changed(key.split('.')[0], true); this.changed(key.split('.')[0], true);
...@@ -3078,9 +2995,7 @@ class Model { ...@@ -3078,9 +2995,7 @@ class Model {
return this._changed[key] || false; return this._changed[key] || false;
} }
var changed = Object.keys(this.dataValues).filter(function(key) { const changed = Object.keys(this.dataValues).filter(key => this.changed(key));
return this.changed(key);
}.bind(this));
return changed.length ? changed : false; return changed.length ? changed : false;
} }
...@@ -3098,26 +3013,21 @@ class Model { ...@@ -3098,26 +3013,21 @@ class Model {
return this._previousDataValues[key]; return this._previousDataValues[key];
} }
return _.pickBy(this._previousDataValues, function(value, key) { return _.pickBy(this._previousDataValues, (value, key) => this.changed(key));
return this.changed(key);
}.bind(this));
} }
_setInclude(key, value, options) { _setInclude(key, value, options) {
if (!Array.isArray(value)) value = [value]; if (!Array.isArray(value)) value = [value];
if (value[0] instanceof Model) { if (value[0] instanceof Model) {
value = value.map(function(instance) { value = value.map(instance => instance.dataValues);
return instance.dataValues;
});
} }
var include = this.$options.includeMap[key] const include = this.$options.includeMap[key];
, association = include.association const association = include.association;
, self = this const accessor = key;
, accessor = key const primaryKeyAttribute = include.model.primaryKeyAttribute;
, childOptions let childOptions;
, primaryKeyAttribute = include.model.primaryKeyAttribute let isEmpty;
, isEmpty;
if (!isEmpty) { if (!isEmpty) {
childOptions = { childOptions = {
...@@ -3137,10 +3047,10 @@ class Model { ...@@ -3137,10 +3047,10 @@ class Model {
} }
isEmpty = (value && value[primaryKeyAttribute] === null) || (value === null); isEmpty = (value && value[primaryKeyAttribute] === null) || (value === null);
self[accessor] = self.dataValues[accessor] = isEmpty ? null : include.model.build(value, childOptions); this[accessor] = this.dataValues[accessor] = isEmpty ? null : include.model.build(value, childOptions);
} else { } else {
isEmpty = value[0] && value[0][primaryKeyAttribute] === null; isEmpty = value[0] && value[0][primaryKeyAttribute] === null;
self[accessor] = self.dataValues[accessor] = isEmpty ? [] : include.model.bulkBuild(value, childOptions); this[accessor] = this.dataValues[accessor] = isEmpty ? [] : include.model.bulkBuild(value, childOptions);
} }
} }
} }
...@@ -3191,14 +3101,13 @@ class Model { ...@@ -3191,14 +3101,13 @@ class Model {
} }
} }
var self = this const primaryKeyName = this.constructor.primaryKeyAttribute;
, primaryKeyName = this.constructor.primaryKeyAttribute const primaryKeyAttribute = primaryKeyName && this.constructor.rawAttributes[primaryKeyName];
, primaryKeyAttribute = primaryKeyName && this.constructor.rawAttributes[primaryKeyName] const createdAtAttr = this.constructor._timestampAttributes.createdAt;
, updatedAtAttr = this.constructor._timestampAttributes.updatedAt const hook = this.isNewRecord ? 'Create' : 'Update';
, createdAtAttr = this.constructor._timestampAttributes.createdAt const wasNewRecord = this.isNewRecord;
, hook = self.isNewRecord ? 'Create' : 'Update' const now = Utils.now(this.sequelize.options.dialect);
, wasNewRecord = this.isNewRecord let updatedAtAttr = this.constructor._timestampAttributes.updatedAt;
, now = Utils.now(this.sequelize.options.dialect);
if (updatedAtAttr && options.fields.length >= 1 && options.fields.indexOf(updatedAtAttr) === -1) { if (updatedAtAttr && options.fields.length >= 1 && options.fields.indexOf(updatedAtAttr) === -1) {
options.fields.push(updatedAtAttr); options.fields.push(updatedAtAttr);
...@@ -3206,9 +3115,7 @@ class Model { ...@@ -3206,9 +3115,7 @@ class Model {
if (options.silent === true && !(this.isNewRecord && this.get(updatedAtAttr, {raw: true}))) { if (options.silent === true && !(this.isNewRecord && this.get(updatedAtAttr, {raw: true}))) {
// UpdateAtAttr might have been added as a result of Object.keys(Model.attributes). In that case we have to remove it again // UpdateAtAttr might have been added as a result of Object.keys(Model.attributes). In that case we have to remove it again
Utils._.remove(options.fields, function(val) { Utils._.remove(options.fields, val => val === updatedAtAttr);
return val === updatedAtAttr;
});
updatedAtAttr = false; updatedAtAttr = false;
} }
...@@ -3236,34 +3143,33 @@ class Model { ...@@ -3236,34 +3143,33 @@ class Model {
this.dataValues[createdAtAttr] = this.constructor.$getDefaultTimestamp(createdAtAttr) || now; this.dataValues[createdAtAttr] = this.constructor.$getDefaultTimestamp(createdAtAttr) || now;
} }
return Promise.bind(this).then(function() { return Promise.try(() => {
// Validate // Validate
if (options.validate) { if (options.validate) {
return this.validate(options); return this.validate(options);
} }
}).then(function() { }).then(() => {
return Promise.bind(this).then(function() {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
var beforeHookValues = _.pick(this.dataValues, options.fields) const beforeHookValues = _.pick(this.dataValues, options.fields);
, afterHookValues let ignoreChanged = _.difference(this.changed(), options.fields); // In case of update where it's only supposed to update the passed values and the hook values
, hookChanged let hookChanged;
, ignoreChanged = _.difference(this.changed(), options.fields); // In case of update where it's only supposed to update the passed values and the hook values let afterHookValues;
if (updatedAtAttr && options.fields.indexOf(updatedAtAttr) !== -1) { if (updatedAtAttr && options.fields.indexOf(updatedAtAttr) !== -1) {
ignoreChanged = _.without(ignoreChanged, updatedAtAttr); ignoreChanged = _.without(ignoreChanged, updatedAtAttr);
} }
return this.constructor.runHooks('before' + hook, this, options).bind(this).then(function() { return this.constructor.runHooks('before' + hook, this, options).then(() => {
if (options.defaultFields && !this.isNewRecord) { if (options.defaultFields && !this.isNewRecord) {
afterHookValues = _.pick(this.dataValues, _.difference(this.changed(), ignoreChanged)); afterHookValues = _.pick(this.dataValues, _.difference(this.changed(), ignoreChanged));
hookChanged = []; hookChanged = [];
Object.keys(afterHookValues).forEach(function (key) { for (const key of Object.keys(afterHookValues)) {
if (afterHookValues[key] !== beforeHookValues[key]) { if (afterHookValues[key] !== beforeHookValues[key]) {
hookChanged.push(key); hookChanged.push(key);
} }
}); }
options.fields = _.uniq(options.fields.concat(hookChanged)); options.fields = _.uniq(options.fields.concat(hookChanged));
} }
...@@ -3273,129 +3179,121 @@ class Model { ...@@ -3273,129 +3179,121 @@ class Model {
// Validate again // Validate again
options.skip = _.difference(Object.keys(this.constructor.rawAttributes), hookChanged); options.skip = _.difference(Object.keys(this.constructor.rawAttributes), hookChanged);
return this.validate(options).then(function() { return this.validate(options).then(() => {
delete options.skip; delete options.skip;
}); });
} }
} }
}); });
} }
}).then(function() { }).then(() => {
if (!options.fields.length) return this; if (!options.fields.length) return this;
if (!this.isNewRecord) return this; if (!this.isNewRecord) return this;
if (!this.$options.include || !this.$options.include.length) return this; if (!this.$options.include || !this.$options.include.length) return this;
// Nested creation for BelongsTo relations // Nested creation for BelongsTo relations
return Promise.map(this.$options.include.filter(function (include) { return Promise.map(this.$options.include.filter(include => include.association instanceof BelongsTo), include => {
return include.association instanceof BelongsTo; const instance = this.get(include.as);
}), function (include) {
var instance = self.get(include.as);
if (!instance) return Promise.resolve(); if (!instance) return Promise.resolve();
var includeOptions = _(Utils.cloneDeep(include)) const includeOptions = _(Utils.cloneDeep(include))
.omit(['association']) .omit(['association'])
.defaults({ .defaults({
transaction: options.transaction, transaction: options.transaction,
logging: options.logging, logging: options.logging,
parentRecord: self parentRecord: this
}).value(); }).value();
return instance.save(includeOptions).then(function () { return instance.save(includeOptions).then(() => this[include.association.accessors.set](instance, {save: false, logging: options.logging}));
return self[include.association.accessors.set](instance, {save: false, logging: options.logging});
});
}); });
}) }).then(() => {
.then(function() {
if (!options.fields.length) return this; if (!options.fields.length) return this;
if (!this.changed() && !this.isNewRecord) return this; if (!this.changed() && !this.isNewRecord) return this;
var values = Utils.mapValueFieldNames(this.dataValues, options.fields, this.constructor) let values = Utils.mapValueFieldNames(this.dataValues, options.fields, this.constructor);
, query = null let query = null;
, args = []; let args = [];
if (self.isNewRecord) { if (this.isNewRecord) {
query = 'insert'; query = 'insert';
args = [self, self.constructor.getTableName(options), values, options]; args = [this, this.constructor.getTableName(options), values, options];
} else { } else {
var where = this.where(); let where = this.where();
where = Utils.mapValueFieldNames(where, Object.keys(where), this.constructor); where = Utils.mapValueFieldNames(where, Object.keys(where), this.constructor);
query = 'update'; query = 'update';
args = [self, self.constructor.getTableName(options), values, where, options]; args = [this, this.constructor.getTableName(options), values, where, options];
} }
return self.sequelize.getQueryInterface()[query].apply(self.sequelize.getQueryInterface(), args) return this.sequelize.getQueryInterface()[query].apply(this.sequelize.getQueryInterface(), args)
.then(function(result) { .then(result => {
// Transfer database generated values (defaults, autoincrement, etc) // Transfer database generated values (defaults, autoincrement, etc)
Object.keys(self.constructor.rawAttributes).forEach(function (attr) { for (const attr of Object.keys(this.constructor.rawAttributes)) {
if (self.constructor.rawAttributes[attr].field && if (this.constructor.rawAttributes[attr].field &&
values[self.constructor.rawAttributes[attr].field] !== undefined && values[this.constructor.rawAttributes[attr].field] !== undefined &&
self.constructor.rawAttributes[attr].field !== attr this.constructor.rawAttributes[attr].field !== attr
) { ) {
values[attr] = values[self.constructor.rawAttributes[attr].field]; values[attr] = values[this.constructor.rawAttributes[attr].field];
delete values[self.constructor.rawAttributes[attr].field]; delete values[this.constructor.rawAttributes[attr].field];
}
} }
});
values = _.extend(values, result.dataValues); values = _.extend(values, result.dataValues);
result.dataValues = _.extend(result.dataValues, values); result.dataValues = _.extend(result.dataValues, values);
return result; return result;
}) })
.tap(function(result) { .tap(result => {
if (!wasNewRecord) return self; if (!wasNewRecord) return this;
if (!self.$options.include || !self.$options.include.length) return self; if (!this.$options.include || !this.$options.include.length) return this;
// Nested creation for HasOne/HasMany/BelongsToMany relations // Nested creation for HasOne/HasMany/BelongsToMany relations
return Promise.map(self.$options.include.filter(function (include) { return Promise.map(this.$options.include.filter(include => !(include.association instanceof BelongsTo)), include => {
return !(include.association instanceof BelongsTo); let instances = this.get(include.as);
}), function (include) {
var instances = self.get(include.as);
if (!instances) return Promise.resolve(); if (!instances) return Promise.resolve();
if (!Array.isArray(instances)) instances = [instances]; if (!Array.isArray(instances)) instances = [instances];
if (!instances.length) return Promise.resolve(); if (!instances.length) return Promise.resolve();
var includeOptions = _(Utils.cloneDeep(include)) const includeOptions = _(Utils.cloneDeep(include))
.omit(['association']) .omit(['association'])
.defaults({ .defaults({
transaction: options.transaction, transaction: options.transaction,
logging: options.logging, logging: options.logging,
parentRecord: self parentRecord: this
}).value(); }).value();
// Instances will be updated in place so we can safely treat HasOne like a HasMany // Instances will be updated in place so we can safely treat HasOne like a HasMany
return Promise.map(instances, function (instance) { return Promise.map(instances, instance => {
if (include.association instanceof BelongsToMany) { if (include.association instanceof BelongsToMany) {
return instance.save(includeOptions).then(function () { return instance.save(includeOptions).then(() => {
var values = {}; const values = {};
values[include.association.foreignKey] = self.get(self.constructor.primaryKeyAttribute, {raw: true}); values[include.association.foreignKey] = this.get(this.constructor.primaryKeyAttribute, {raw: true});
values[include.association.otherKey] = instance.get(instance.constructor.primaryKeyAttribute, {raw: true}); values[include.association.otherKey] = instance.get(instance.constructor.primaryKeyAttribute, {raw: true});
return include.association.throughModel.create(values, includeOptions); return include.association.throughModel.create(values, includeOptions);
}); });
} else { } else {
instance.set(include.association.foreignKey, self.get(self.constructor.primaryKeyAttribute, {raw: true})); instance.set(include.association.foreignKey, this.get(this.constructor.primaryKeyAttribute, {raw: true}));
return instance.save(includeOptions); return instance.save(includeOptions);
} }
}); });
}); });
}) })
.tap(function(result) { .tap(result => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return self.constructor.runHooks('after' + hook, result, options); return this.constructor.runHooks('after' + hook, result, options);
} }
}) })
.then(function(result) { .then(result => {
options.fields.forEach(function (field) { for (const field of options.fields) {
result._previousDataValues[field] = result.dataValues[field]; result._previousDataValues[field] = result.dataValues[field];
self.changed(field, false); this.changed(field, false);
}); }
self.isNewRecord = false; this.isNewRecord = false;
return result; return result;
}); });
}); });
});
} }
/* /*
...@@ -3414,15 +3312,15 @@ class Model { ...@@ -3414,15 +3312,15 @@ class Model {
include: this.$options.include || null include: this.$options.include || null
}); });
return this.constructor.findOne(options).bind(this) return this.constructor.findOne(options)
.tap(function (reload) { .tap(reload => {
if (!reload) { if (!reload) {
throw new sequelizeErrors.InstanceError( throw new sequelizeErrors.InstanceError(
'Instance could not be reloaded because it does not exist anymore (find call returned null)' 'Instance could not be reloaded because it does not exist anymore (find call returned null)'
); );
} }
}) })
.then(function(reload) { .then(reload => {
// update the internal options of the instance // update the internal options of the instance
this.$options = reload.$options; this.$options = reload.$options;
// re-set instance values // re-set instance values
...@@ -3430,7 +3328,8 @@ class Model { ...@@ -3430,7 +3328,8 @@ class Model {
raw: true, raw: true,
reset: true && !options.attributes reset: true && !options.attributes
}); });
}).return(this); return this;
});
} }
/* /*
...@@ -3462,22 +3361,19 @@ class Model { ...@@ -3462,22 +3361,19 @@ class Model {
* @alias updateAttributes * @alias updateAttributes
*/ */
update(values, options) { update(values, options) {
var changedBefore = this.changed() || [] const changedBefore = this.changed() || [];
, sideEffects
, fields
, setOptions;
options = options || {}; options = options || {};
if (Array.isArray(options)) options = {fields: options}; if (Array.isArray(options)) options = {fields: options};
options = Utils.cloneDeep(options); options = Utils.cloneDeep(options);
setOptions = Utils.cloneDeep(options); const setOptions = Utils.cloneDeep(options);
setOptions.attributes = options.fields; setOptions.attributes = options.fields;
this.set(values, setOptions); this.set(values, setOptions);
// Now we need to figure out which fields were actually affected by the setter. // Now we need to figure out which fields were actually affected by the setter.
sideEffects = _.without.apply(this, [this.changed() || []].concat(changedBefore)); const sideEffects = _.without.apply(this, [this.changed() || []].concat(changedBefore));
fields = _.union(Object.keys(values), sideEffects); const fields = _.union(Object.keys(values), sideEffects);
if (!options.fields) { if (!options.fields) {
options.fields = _.intersection(fields, this.changed()); options.fields = _.intersection(fields, this.changed());
...@@ -3505,18 +3401,18 @@ class Model { ...@@ -3505,18 +3401,18 @@ class Model {
force: false force: false
}, options); }, options);
return Promise.bind(this).then(function() { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks('beforeDestroy', this, options); return this.constructor.runHooks('beforeDestroy', this, options);
} }
}).then(function() { }).then(() => {
var where = this.where(); const where = this.where();
if (this.constructor._timestampAttributes.deletedAt && options.force === false) { if (this.constructor._timestampAttributes.deletedAt && options.force === false) {
var attribute = this.constructor.rawAttributes[this.constructor._timestampAttributes.deletedAt] const attribute = this.constructor.rawAttributes[this.constructor._timestampAttributes.deletedAt];
, field = attribute.field || this.constructor._timestampAttributes.deletedAt const field = attribute.field || this.constructor._timestampAttributes.deletedAt;
, values = {}; const values = {};
values[field] = new Date(); values[field] = new Date();
where[field] = attribute.hasOwnProperty('defaultValue') ? attribute.defaultValue : null; where[field] = attribute.hasOwnProperty('defaultValue') ? attribute.defaultValue : null;
...@@ -3527,13 +3423,11 @@ class Model { ...@@ -3527,13 +3423,11 @@ class Model {
} else { } else {
return this.sequelize.getQueryInterface().delete(this, this.constructor.getTableName(options), where, _.assign({ type: QueryTypes.DELETE, limit: null }, options)); return this.sequelize.getQueryInterface().delete(this, this.constructor.getTableName(options), where, _.assign({ type: QueryTypes.DELETE, limit: null }, options));
} }
}).tap(function() { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks('afterDestroy', this, options); return this.constructor.runHooks('afterDestroy', this, options);
} }
}).then(function(result) {
return result;
}); });
} }
...@@ -3554,19 +3448,19 @@ class Model { ...@@ -3554,19 +3448,19 @@ class Model {
force: false force: false
}, options); }, options);
return Promise.bind(this).then(function() { return Promise.try(() => {
// Run before hook // Run before hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks('beforeRestore', this, options); return this.constructor.runHooks('beforeRestore', this, options);
} }
}).then(function() { }).then(() => {
var deletedAtCol = this.constructor._timestampAttributes.deletedAt const deletedAtCol = this.constructor._timestampAttributes.deletedAt;
, deletedAtAttribute = this.constructor.rawAttributes[deletedAtCol] const deletedAtAttribute = this.constructor.rawAttributes[deletedAtCol];
, deletedAtDefaultValue = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null; const deletedAtDefaultValue = deletedAtAttribute.hasOwnProperty('defaultValue') ? deletedAtAttribute.defaultValue : null;
this.setDataValue(deletedAtCol, deletedAtDefaultValue); this.setDataValue(deletedAtCol, deletedAtDefaultValue);
return this.save(_.extend({}, options, {hooks : false, omitNull : false})); return this.save(_.extend({}, options, {hooks : false, omitNull : false}));
}).tap(function() { }).tap(() => {
// Run after hook // Run after hook
if (options.hooks) { if (options.hooks) {
return this.constructor.runHooks('afterRestore', this, options); return this.constructor.runHooks('afterRestore', this, options);
...@@ -3599,10 +3493,8 @@ class Model { ...@@ -3599,10 +3493,8 @@ class Model {
* @return {Promise<this>} * @return {Promise<this>}
*/ */
increment(fields, options) { increment(fields, options) {
var identifier = this.where() const identifier = this.where();
, updatedAtAttr = this.constructor._timestampAttributes.updatedAt const updatedAtAttr = this.constructor._timestampAttributes.updatedAt;
, values = {}
, where;
options = _.defaults({}, options, { options = _.defaults({}, options, {
by: 1, by: 1,
...@@ -3610,12 +3502,13 @@ class Model { ...@@ -3610,12 +3502,13 @@ class Model {
where: {} where: {}
}); });
where = _.extend({}, options.where, identifier); const where = _.extend({}, options.where, identifier);
let values = {};
if (Utils._.isString(fields)) { if (Utils._.isString(fields)) {
values[fields] = options.by; values[fields] = options.by;
} else if (Utils._.isArray(fields)) { } else if (Utils._.isArray(fields)) {
Utils._.each(fields, function(field) { Utils._.each(fields, field => {
values[field] = options.by; values[field] = options.by;
}); });
} else { // Assume fields is key-value pairs } else { // Assume fields is key-value pairs
...@@ -3626,13 +3519,13 @@ class Model { ...@@ -3626,13 +3519,13 @@ class Model {
options.attributes[updatedAtAttr] = this.constructor.$getDefaultTimestamp(updatedAtAttr) || Utils.now(this.sequelize.options.dialect); options.attributes[updatedAtAttr] = this.constructor.$getDefaultTimestamp(updatedAtAttr) || Utils.now(this.sequelize.options.dialect);
} }
Object.keys(values).forEach(function(attr) { for (const attr of Object.keys(values)) {
// Field name mapping // Field name mapping
if (this.constructor.rawAttributes[attr] && this.constructor.rawAttributes[attr].field && this.constructor.rawAttributes[attr].field !== attr) { if (this.constructor.rawAttributes[attr] && this.constructor.rawAttributes[attr].field && this.constructor.rawAttributes[attr].field !== attr) {
values[this.constructor.rawAttributes[attr].field] = values[attr]; values[this.constructor.rawAttributes[attr].field] = values[attr];
delete values[attr]; delete values[attr];
} }
}, this); }
return this.sequelize.getQueryInterface().increment(this, this.constructor.getTableName(options), values, where, options).return(this); return this.sequelize.getQueryInterface().increment(this, this.constructor.getTableName(options), values, where, options).return(this);
} }
...@@ -3667,7 +3560,7 @@ class Model { ...@@ -3667,7 +3560,7 @@ class Model {
}); });
if (!Utils._.isString(fields) && !Utils._.isArray(fields)) { // Assume fields is key-value pairs if (!Utils._.isString(fields) && !Utils._.isArray(fields)) { // Assume fields is key-value pairs
Utils._.each(fields, function(value, field) { Utils._.each(fields, (value, field) => {
fields[field] = -value; fields[field] = -value;
}); });
} }
...@@ -3684,19 +3577,16 @@ class Model { ...@@ -3684,19 +3577,16 @@ class Model {
* @return {Boolean} * @return {Boolean}
*/ */
equals(other) { equals(other) {
var self = this;
if (!other || !other.constructor) { if (!other || !other.constructor) {
return false; return false;
} }
if (!(other instanceof self.constructor)) { if (!(other instanceof this.constructor)) {
return false; return false;
} }
return Utils._.every(this.constructor.primaryKeyAttributes, function(attribute) { return Utils._.every(this.constructor.primaryKeyAttributes, attribute => this.get(attribute, {raw: true}) === other.get(attribute, {raw: true}));
return self.get(attribute, {raw: true}) === other.get(attribute, {raw: true});
});
} }
/** /**
...@@ -3706,11 +3596,7 @@ class Model { ...@@ -3706,11 +3596,7 @@ class Model {
* @return {Boolean} * @return {Boolean}
*/ */
equalsOneOf(others) { equalsOneOf(others) {
var self = this; return _.some(others, other => this.equals(other));
return _.some(others, function(other) {
return self.equals(other);
});
} }
setValidators(attribute, validators) { setValidators(attribute, validators) {
......
'use strict'; 'use strict';
var Attribute = function(options) { class Attribute {
constructor(options) {
if (options.type === undefined) options = {type: options}; if (options.type === undefined) options = {type: options};
this.type = options.type; this.type = options.type;
}; }
}
module.exports = Attribute; module.exports = Attribute;
module.exports.Attribute = Attribute;
module.exports.default = Attribute;
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!