UNPKG

sequelize

Version:

Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Amazon Redshift and Snowflake’s Data Cloud. It features solid transaction support, relations, eager and lazy loading, read replication and more.

317 lines (316 loc) 11.9 kB
"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