import {QueryBuilder} from "./QueryBuilder"; import {ObjectLiteral} from "../common/ObjectLiteral"; import {QueryExpressionMap} from "./QueryExpressionMap"; /** * Allows to work with entity relations and perform specific operations with those relations. * * todo: add transactions everywhere */ export class RelationRemover { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- constructor(protected queryBuilder: QueryBuilder, protected expressionMap: QueryExpressionMap) { } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- /** * Performs remove operation on a relation. */ async remove(value: any|any[]): Promise { const relation = this.expressionMap.relationMetadata; if (relation.isOneToMany) { // if (this.expressionMap.of instanceof Array) // throw new Error(`You cannot update relations of multiple entities with the same related object. Provide a single entity into .of method.`); // DELETE FROM post WHERE post.categoryId = of AND post.id = id const ofs = this.expressionMap.of instanceof Array ? this.expressionMap.of : [this.expressionMap.of]; const values = value instanceof Array ? value : [value]; const updateSet: ObjectLiteral = {}; relation.inverseRelation!.joinColumns.forEach(column => { updateSet[column.propertyName] = null; }); const parameters: ObjectLiteral = {}; const conditions: string[] = []; ofs.forEach((of, ofIndex) => { conditions.push(...values.map((value, valueIndex) => { return [ ...relation.inverseRelation!.joinColumns.map((column, columnIndex) => { const parameterName = "joinColumn_" + ofIndex + "_" + valueIndex + "_" + columnIndex; parameters[parameterName] = of instanceof Object ? column.referencedColumn!.getEntityValue(of) : of; return `${column.propertyPath} = :${parameterName}`; }), ...relation.inverseRelation!.entityMetadata.primaryColumns.map((column, columnIndex) => { const parameterName = "primaryColumn_" + valueIndex + "_" + valueIndex + "_" + columnIndex; parameters[parameterName] = value instanceof Object ? column.getEntityValue(value) : value; return `${column.propertyPath} = :${parameterName}`; }) ].join(" AND "); })); }); 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 { // many to many const junctionMetadata = relation.junctionEntityMetadata!; const ofs = this.expressionMap.of instanceof Array ? this.expressionMap.of : [this.expressionMap.of]; const values = value instanceof Array ? value : [value]; const firstColumnValues = relation.isManyToManyOwner ? ofs : values; const secondColumnValues = relation.isManyToManyOwner ? values : ofs; const parameters: ObjectLiteral = {}; const conditions: string[] = []; firstColumnValues.forEach((firstColumnVal, firstColumnValIndex) => { conditions.push(...secondColumnValues.map((secondColumnVal, secondColumnValIndex) => { return [ ...junctionMetadata.ownerColumns.map((column, columnIndex) => { const parameterName = "firstValue_" + firstColumnValIndex + "_" + secondColumnValIndex + "_" + columnIndex; parameters[parameterName] = firstColumnVal instanceof Object ? column.referencedColumn!.getEntityValue(firstColumnVal) : firstColumnVal; return `${column.databaseName} = :${parameterName}`; }), ...junctionMetadata.inverseColumns.map((column, columnIndex) => { const parameterName = "secondValue_" + firstColumnValIndex + "_" + secondColumnValIndex + "_" + columnIndex; parameters[parameterName] = firstColumnVal instanceof Object ? column.referencedColumn!.getEntityValue(secondColumnVal) : secondColumnVal; return `${column.databaseName} = :${parameterName}`; }) ].join(" AND "); })); }); const condition = conditions.map(str => "(" + str + ")").join(" OR "); await this.queryBuilder .createQueryBuilder() .delete() .from(junctionMetadata.tableName) .where(condition) .setParameters(parameters) .execute(); } } }