BE-SPAN/node_modules/sequelize-oracle/lib/associations/has-many.js
githubna-ilham 722cd440e8 first commit
2024-10-20 22:04:16 +07:00

344 lines
10 KiB
JavaScript

'use strict';
var Utils = require('./../utils')
, Helpers = require('./helpers')
, _ = require('lodash')
, Association = require('./base')
, CounterCache = require('../plugins/counter-cache')
, util = require('util');
var HasMany = function(source, target, options) {
Association.call(this);
this.associationType = 'HasMany';
this.source = source;
this.target = target;
this.targetAssociation = null;
this.options = options || {};
this.sequelize = source.modelManager.sequelize;
this.through = options.through;
this.scope = options.scope;
this.isMultiAssociation = true;
this.isSelfAssociation = this.source === this.target;
this.as = this.options.as;
if (this.options.through) {
throw new Error('N:M associations are not supported with hasMany. Use belongsToMany instead');
}
if (_.isObject(this.options.foreignKey)) {
this.foreignKeyAttribute = this.options.foreignKey;
this.foreignKey = this.foreignKeyAttribute.name || this.foreignKeyAttribute.fieldName;
} else {
this.foreignKeyAttribute = {};
this.foreignKey = this.options.foreignKey;
}
/*
* If self association, this is the target association
*/
if (this.isSelfAssociation) {
this.targetAssociation = this;
}
if (this.as) {
this.isAliased = true;
if (_.isPlainObject(this.as)) {
this.options.name = this.as;
this.as = this.as.plural;
} else {
this.options.name = {
plural: this.as,
singular: Utils.singularize(this.as)
};
}
} else {
this.as = this.target.options.name.plural;
this.options.name = this.target.options.name;
}
this.associationAccessor = this.as;
// Get singular and plural names, trying to uppercase the first letter, unless the model forbids it
var plural = Utils.uppercaseFirst(this.options.name.plural)
, singular = Utils.uppercaseFirst(this.options.name.singular);
this.accessors = {
get: 'get' + plural,
set: 'set' + plural,
addMultiple: 'add' + plural,
add: 'add' + singular,
create: 'create' + singular,
remove: 'remove' + singular,
removeMultiple: 'remove' + plural,
hasSingle: 'has' + singular,
hasAll: 'has' + plural
};
if (this.options.counterCache) {
new CounterCache(this, this.options.counterCache !== true ? this.options.counterCache : {});
}
};
util.inherits(HasMany, Association);
// the id is in the target table
// or in an extra table which connects two tables
HasMany.prototype.injectAttributes = function() {
this.identifier = this.foreignKey || _.camelizeIf(
[
_.underscoredIf(this.source.options.name.singular, this.source.options.underscored),
this.source.primaryKeyAttribute
].join('_'),
!this.source.options.underscored
);
var newAttributes = {};
var constraintOptions = _.clone(this.options); // Create a new options object for use with addForeignKeyConstraints, to avoid polluting this.options in case it is later used for a n:m
newAttributes[this.identifier] = _.defaults(this.foreignKeyAttribute, { type: this.options.keyType || this.source.rawAttributes[this.source.primaryKeyAttribute].type });
if (this.options.constraints !== false) {
constraintOptions.onDelete = constraintOptions.onDelete || 'SET NULL';
constraintOptions.onUpdate = constraintOptions.onUpdate || 'CASCADE';
}
Helpers.addForeignKeyConstraints(newAttributes[this.identifier], this.source, this.target, constraintOptions);
Utils.mergeDefaults(this.target.rawAttributes, newAttributes);
this.identifierField = this.target.rawAttributes[this.identifier].field || this.identifier;
this.target.refreshAttributes();
this.source.refreshAttributes();
Helpers.checkNamingCollision(this);
return this;
};
HasMany.prototype.injectGetter = function(obj) {
var association = this;
obj[this.accessors.get] = function(options) {
var scopeWhere = association.scope ? {} : null
, Model = association.target;
options = association.target.__optClone(options) || {};
if (association.scope) {
_.assign(scopeWhere, association.scope);
}
options.where = {
$and: [
new Utils.where(
association.target.rawAttributes[association.identifier],
this.get(association.source.primaryKeyAttribute, {raw: true})
),
scopeWhere,
options.where
]
};
if (options.hasOwnProperty('scope')) {
if (!options.scope) {
Model = Model.unscoped();
} else {
Model = Model.scope(options.scope);
}
}
return Model.all(options);
};
obj[this.accessors.hasSingle] = obj[this.accessors.hasAll] = function(instances, options) {
var where = {};
if (!Array.isArray(instances)) {
instances = [instances];
}
options = options || {};
options.scope = false;
where.$or = instances.map(function (instance) {
if (instance instanceof association.target.Instance) {
return instance.where();
} else {
var _where = {};
_where[association.target.primaryKeyAttribute] = instance;
return _where;
}
});
options.where = {
$and: [
where,
options.where
]
};
return this[association.accessors.get](
options,
{ raw: true }
).then(function(associatedObjects) {
return associatedObjects.length === instances.length;
});
};
return this;
};
HasMany.prototype.injectSetter = function(obj) {
var association = this;
obj[this.accessors.set] = function(newAssociatedObjects, additionalAttributes) {
var options = additionalAttributes || {};
additionalAttributes = additionalAttributes || {};
if (newAssociatedObjects === null) {
newAssociatedObjects = [];
} else {
newAssociatedObjects = association.toInstanceArray(newAssociatedObjects);
}
var instance = this;
return instance[association.accessors.get](_.defaults({
scope: false,
raw: true
}, options)).then(function(oldAssociations) {
var promises = []
, obsoleteAssociations = oldAssociations.filter(function(old) {
return !_.find(newAssociatedObjects, function(obj) {
return obj[association.target.primaryKeyAttribute] === old[association.target.primaryKeyAttribute];
});
})
, unassociatedObjects = newAssociatedObjects.filter(function(obj) {
return !_.find(oldAssociations, function(old) {
return obj[association.target.primaryKeyAttribute] === old[association.target.primaryKeyAttribute];
});
})
, updateWhere
, update;
if (obsoleteAssociations.length > 0) {
update = {};
update[association.identifier] = null;
updateWhere = {};
updateWhere[association.target.primaryKeyAttribute] = obsoleteAssociations.map(function(associatedObject) {
return associatedObject[association.target.primaryKeyAttribute];
});
promises.push(association.target.unscoped().update(
update,
_.defaults({
where: updateWhere
}, options)
));
}
if (unassociatedObjects.length > 0) {
updateWhere = {};
update = {};
update[association.identifier] = instance.get(association.source.primaryKeyAttribute);
_.assign(update, association.scope);
updateWhere[association.target.primaryKeyAttribute] = unassociatedObjects.map(function(unassociatedObject) {
return unassociatedObject[association.target.primaryKeyAttribute];
});
promises.push(association.target.unscoped().update(
update,
_.defaults({
where: updateWhere
}, options)
));
}
return Utils.Promise.all(promises).return(instance);
});
};
obj[this.accessors.addMultiple] = obj[this.accessors.add] = function(newInstances, options) {
// If newInstance is null or undefined, no-op
if (!newInstances) return Utils.Promise.resolve();
options = options || {};
var instance = this, update = {}, where = {};
newInstances = association.toInstanceArray(newInstances);
update[association.identifier] = instance.get(association.source.primaryKeyAttribute);
_.assign(update, association.scope);
where[association.target.primaryKeyAttribute] = newInstances.map(function (unassociatedObject) {
return unassociatedObject.get(association.target.primaryKeyAttribute);
});
return association.target.unscoped().update(
update,
_.defaults({
where: where
}, options)
).return(instance);
};
obj[this.accessors.removeMultiple] = obj[this.accessors.remove] = function(oldAssociatedObjects, options) {
options = options || {};
oldAssociatedObjects = association.toInstanceArray(oldAssociatedObjects);
var update = {};
update[association.identifier] = null;
var where = {};
where[association.identifier] = this.get(association.source.primaryKeyAttribute);
where[association.target.primaryKeyAttribute] = oldAssociatedObjects.map(function (oldAssociatedObject) { return oldAssociatedObject.get(association.target.primaryKeyAttribute); });
return association.target.unscoped().update(
update,
_.defaults({
where: where
}, options)
).return(this);
};
return this;
};
HasMany.prototype.injectCreator = function(obj) {
var association = this;
obj[this.accessors.create] = function(values, options) {
var instance = this;
options = options || {};
if (Array.isArray(options)) {
options = {
fields: options
};
}
if (values === undefined) {
values = {};
}
if (association.scope) {
Object.keys(association.scope).forEach(function (attribute) {
values[attribute] = association.scope[attribute];
if (options.fields) options.fields.push(attribute);
});
}
values[association.identifier] = instance.get(association.source.primaryKeyAttribute);
if (options.fields) options.fields.push(association.identifier);
return association.target.create(values, options);
};
return this;
};
module.exports = HasMany;