You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

317 lines
12 KiB

"use strict";
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
const Utils = require("./../utils");
const Helpers = require("./helpers");
const _ = require("lodash");
const Association = require("./base");
const Op = require("../operators");
class HasMany extends Association {
constructor(source, target, options) {
super(source, target, options);
this.associationType = "HasMany";
this.targetAssociation = null;
this.sequelize = source.sequelize;
this.isMultiAssociation = true;
this.foreignKeyAttribute = {};
if (this.options.through) {
throw new Error("N:M associations are not supported with hasMany. Use belongsToMany instead");
}
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;
}
if (_.isObject(this.options.foreignKey)) {
this.foreignKeyAttribute = this.options.foreignKey;
this.foreignKey = this.foreignKeyAttribute.name || this.foreignKeyAttribute.fieldName;
} else if (this.options.foreignKey) {
this.foreignKey = this.options.foreignKey;
}
if (!this.foreignKey) {
this.foreignKey = Utils.camelize([
this.source.options.name.singular,
this.source.primaryKeyAttribute
].join("_"));
}
if (this.target.rawAttributes[this.foreignKey]) {
this.identifierField = this.target.rawAttributes[this.foreignKey].field || this.foreignKey;
this.foreignKeyField = this.target.rawAttributes[this.foreignKey].field || this.foreignKey;
}
this.sourceKey = this.options.sourceKey || this.source.primaryKeyAttribute;
if (this.source.rawAttributes[this.sourceKey]) {
this.sourceKeyAttribute = this.sourceKey;
this.sourceKeyField = this.source.rawAttributes[this.sourceKey].field || this.sourceKey;
} else {
this.sourceKeyAttribute = this.source.primaryKeyAttribute;
this.sourceKeyField = this.source.primaryKeyField;
}
const plural = _.upperFirst(this.options.name.plural);
const singular = _.upperFirst(this.options.name.singular);
this.associationAccessor = this.as;
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}`,
count: `count${plural}`
};
}
_injectAttributes() {
const newAttributes = {
[this.foreignKey]: __spreadValues({
type: this.options.keyType || this.source.rawAttributes[this.sourceKeyAttribute].type,
allowNull: true
}, this.foreignKeyAttribute)
};
const constraintOptions = __spreadValues({}, this.options);
if (this.options.constraints !== false) {
const target = this.target.rawAttributes[this.foreignKey] || newAttributes[this.foreignKey];
constraintOptions.onDelete = constraintOptions.onDelete || (target.allowNull ? "SET NULL" : "CASCADE");
constraintOptions.onUpdate = constraintOptions.onUpdate || "CASCADE";
}
Helpers.addForeignKeyConstraints(newAttributes[this.foreignKey], this.source, this.target, constraintOptions, this.sourceKeyField);
Utils.mergeDefaults(this.target.rawAttributes, newAttributes);
this.target.refreshAttributes();
this.source.refreshAttributes();
this.identifierField = this.target.rawAttributes[this.foreignKey].field || this.foreignKey;
this.foreignKeyField = this.target.rawAttributes[this.foreignKey].field || this.foreignKey;
this.sourceKeyField = this.source.rawAttributes[this.sourceKey].field || this.sourceKey;
Helpers.checkNamingCollision(this);
return this;
}
mixin(obj) {
const methods = ["get", "count", "hasSingle", "hasAll", "set", "add", "addMultiple", "remove", "removeMultiple", "create"];
const aliases = {
hasSingle: "has",
hasAll: "has",
addMultiple: "add",
removeMultiple: "remove"
};
Helpers.mixinMethods(this, obj, methods, aliases);
}
async get(instances, options = {}) {
const where = {};
let Model = this.target;
let instance;
let values;
if (!Array.isArray(instances)) {
instance = instances;
instances = void 0;
}
options = __spreadValues({}, options);
if (this.scope) {
Object.assign(where, this.scope);
}
if (instances) {
values = instances.map((_instance) => _instance.get(this.sourceKey, { raw: true }));
if (options.limit && instances.length > 1) {
options.groupedLimit = {
limit: options.limit,
on: this,
values
};
delete options.limit;
} else {
where[this.foreignKey] = {
[Op.in]: values
};
delete options.groupedLimit;
}
} else {
where[this.foreignKey] = instance.get(this.sourceKey, { raw: true });
}
options.where = options.where ? { [Op.and]: [where, options.where] } : where;
if (Object.prototype.hasOwnProperty.call(options, "scope")) {
if (!options.scope) {
Model = Model.unscoped();
} else {
Model = Model.scope(options.scope);
}
}
if (Object.prototype.hasOwnProperty.call(options, "schema")) {
Model = Model.schema(options.schema, options.schemaDelimiter);
}
const results = await Model.findAll(options);
if (instance)
return results;
const result = {};
for (const _instance of instances) {
result[_instance.get(this.sourceKey, { raw: true })] = [];
}
for (const _instance of results) {
result[_instance.get(this.foreignKey, { raw: true })].push(_instance);
}
return result;
}
async count(instance, options) {
options = Utils.cloneDeep(options);
options.attributes = [
[
this.sequelize.fn("COUNT", this.sequelize.col(`${this.target.name}.${this.target.primaryKeyField}`)),
"count"
]
];
options.raw = true;
options.plain = true;
const result = await this.get(instance, options);
return parseInt(result.count, 10);
}
async has(sourceInstance, targetInstances, options) {
const where = {};
if (!Array.isArray(targetInstances)) {
targetInstances = [targetInstances];
}
options = __spreadProps(__spreadValues({}, options), {
scope: false,
attributes: [this.target.primaryKeyAttribute],
raw: true
});
where[Op.or] = targetInstances.map((instance) => {
if (instance instanceof this.target) {
return instance.where();
}
return {
[this.target.primaryKeyAttribute]: instance
};
});
options.where = {
[Op.and]: [
where,
options.where
]
};
const associatedObjects = await this.get(sourceInstance, options);
return associatedObjects.length === targetInstances.length;
}
async set(sourceInstance, targetInstances, options) {
if (targetInstances === null) {
targetInstances = [];
} else {
targetInstances = this.toInstanceArray(targetInstances);
}
const oldAssociations = await this.get(sourceInstance, __spreadProps(__spreadValues({}, options), { scope: false, raw: true }));
const promises = [];
const obsoleteAssociations = oldAssociations.filter((old) => !targetInstances.find((obj) => obj[this.target.primaryKeyAttribute] === old[this.target.primaryKeyAttribute]));
const unassociatedObjects = targetInstances.filter((obj) => !oldAssociations.find((old) => obj[this.target.primaryKeyAttribute] === old[this.target.primaryKeyAttribute]));
let updateWhere;
let update;
if (obsoleteAssociations.length > 0) {
update = {};
update[this.foreignKey] = null;
updateWhere = {
[this.target.primaryKeyAttribute]: obsoleteAssociations.map((associatedObject) => associatedObject[this.target.primaryKeyAttribute])
};
promises.push(this.target.unscoped().update(update, __spreadProps(__spreadValues({}, options), {
where: updateWhere
})));
}
if (unassociatedObjects.length > 0) {
updateWhere = {};
update = {};
update[this.foreignKey] = sourceInstance.get(this.sourceKey);
Object.assign(update, this.scope);
updateWhere[this.target.primaryKeyAttribute] = unassociatedObjects.map((unassociatedObject) => unassociatedObject[this.target.primaryKeyAttribute]);
promises.push(this.target.unscoped().update(update, __spreadProps(__spreadValues({}, options), {
where: updateWhere
})));
}
await Promise.all(promises);
return sourceInstance;
}
async add(sourceInstance, targetInstances, options = {}) {
if (!targetInstances)
return Promise.resolve();
targetInstances = this.toInstanceArray(targetInstances);
const update = __spreadValues({
[this.foreignKey]: sourceInstance.get(this.sourceKey)
}, this.scope);
const where = {
[this.target.primaryKeyAttribute]: targetInstances.map((unassociatedObject) => unassociatedObject.get(this.target.primaryKeyAttribute))
};
await this.target.unscoped().update(update, __spreadProps(__spreadValues({}, options), { where }));
return sourceInstance;
}
async remove(sourceInstance, targetInstances, options = {}) {
const update = {
[this.foreignKey]: null
};
targetInstances = this.toInstanceArray(targetInstances);
const where = {
[this.foreignKey]: sourceInstance.get(this.sourceKey),
[this.target.primaryKeyAttribute]: targetInstances.map((targetInstance) => targetInstance.get(this.target.primaryKeyAttribute))
};
await this.target.unscoped().update(update, __spreadProps(__spreadValues({}, options), { where }));
return this;
}
async create(sourceInstance, values, options = {}) {
if (Array.isArray(options)) {
options = {
fields: options
};
}
if (values === void 0) {
values = {};
}
if (this.scope) {
for (const attribute of Object.keys(this.scope)) {
values[attribute] = this.scope[attribute];
if (options.fields)
options.fields.push(attribute);
}
}
values[this.foreignKey] = sourceInstance.get(this.sourceKey);
if (options.fields)
options.fields.push(this.foreignKey);
return await this.target.create(values, options);
}
verifyAssociationAlias(alias) {
if (typeof alias === "string") {
return this.as === alias;
}
if (alias && alias.plural) {
return this.as === alias.plural;
}
return !this.isAliased;
}
}
module.exports = HasMany;
module.exports.HasMany = HasMany;
module.exports.default = HasMany;
//# sourceMappingURL=has-many.js.map