UNPKG

typeorm

Version:

Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.

149 lines (147 loc) 6.68 kB
import { TypeORMError } from "../error"; import { ObjectUtils } from "../util/ObjectUtils"; /** * Allows to work with entity relations and perform specific operations with those relations. * * todo: add transactions everywhere */ export class RelationUpdater { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- constructor(queryBuilder, expressionMap) { this.queryBuilder = queryBuilder; this.expressionMap = expressionMap; } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- /** * Performs set or add operation on a relation. */ async update(value) { const relation = this.expressionMap.relationMetadata; if (relation.isManyToOne || relation.isOneToOneOwner) { const updateSet = relation.joinColumns.reduce((updateSet, joinColumn) => { const relationValue = ObjectUtils.isObject(value) ? joinColumn.referencedColumn.getEntityValue(value) : value; joinColumn.setEntityValue(updateSet, relationValue); return updateSet; }, {}); if (!this.expressionMap.of || (Array.isArray(this.expressionMap.of) && !this.expressionMap.of.length)) return; await this.queryBuilder .createQueryBuilder() .update(relation.entityMetadata.target) .set(updateSet) .whereInIds(this.expressionMap.of) .execute(); } else if ((relation.isOneToOneNotOwner || relation.isOneToMany) && value === null) { // we handle null a bit different way const updateSet = {}; relation.inverseRelation.joinColumns.forEach((column) => { updateSet[column.propertyName] = null; }); const ofs = Array.isArray(this.expressionMap.of) ? this.expressionMap.of : [this.expressionMap.of]; const parameters = {}; const conditions = []; ofs.forEach((of, ofIndex) => { relation.inverseRelation.joinColumns.map((column, columnIndex) => { const parameterName = "joinColumn_" + ofIndex + "_" + columnIndex; parameters[parameterName] = ObjectUtils.isObject(of) ? column.referencedColumn.getEntityValue(of) : of; conditions.push(`${column.propertyPath} = :${parameterName}`); }); }); const condition = conditions .map((str) => "(" + str + ")") .join(" OR "); if (!condition) return; await this.queryBuilder .createQueryBuilder() .update(relation.inverseEntityMetadata.target) .set(updateSet) .where(condition) .setParameters(parameters) .execute(); } else if (relation.isOneToOneNotOwner || relation.isOneToMany) { if (Array.isArray(this.expressionMap.of)) throw new TypeORMError(`You cannot update relations of multiple entities with the same related object. Provide a single entity into .of method.`); const of = this.expressionMap.of; const updateSet = relation.inverseRelation.joinColumns.reduce((updateSet, joinColumn) => { const relationValue = ObjectUtils.isObject(of) ? joinColumn.referencedColumn.getEntityValue(of) : of; joinColumn.setEntityValue(updateSet, relationValue); return updateSet; }, {}); if (!value || (Array.isArray(value) && !value.length)) return; await this.queryBuilder .createQueryBuilder() .update(relation.inverseEntityMetadata.target) .set(updateSet) .whereInIds(value) .execute(); } else { // many to many const junctionMetadata = relation.junctionEntityMetadata; const ofs = Array.isArray(this.expressionMap.of) ? this.expressionMap.of : [this.expressionMap.of]; const values = Array.isArray(value) ? value : [value]; const firstColumnValues = relation.isManyToManyOwner ? ofs : values; const secondColumnValues = relation.isManyToManyOwner ? values : ofs; const bulkInserted = []; firstColumnValues.forEach((firstColumnVal) => { secondColumnValues.forEach((secondColumnVal) => { const inserted = {}; junctionMetadata.ownerColumns.forEach((column) => { inserted[column.databaseName] = ObjectUtils.isObject(firstColumnVal) ? column.referencedColumn.getEntityValue(firstColumnVal) : firstColumnVal; }); junctionMetadata.inverseColumns.forEach((column) => { inserted[column.databaseName] = ObjectUtils.isObject(secondColumnVal) ? column.referencedColumn.getEntityValue(secondColumnVal) : secondColumnVal; }); bulkInserted.push(inserted); }); }); if (!bulkInserted.length) return; if (this.queryBuilder.connection.driver.options.type === "oracle" || this.queryBuilder.connection.driver.options.type === "sap") { await Promise.all(bulkInserted.map((value) => { return this.queryBuilder .createQueryBuilder() .insert() .into(junctionMetadata.tableName) .values(value) .execute(); })); } else { await this.queryBuilder .createQueryBuilder() .insert() .into(junctionMetadata.tableName) .values(bulkInserted) .execute(); } } } } //# sourceMappingURL=RelationUpdater.js.map