From cbc806e61d30d02986ff244982405642c69dec2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Thu, 30 May 2024 17:09:46 +0900 Subject: [PATCH] chore(backend): override createJoinExpression --- packages/backend/src/models/_.ts | 68 ++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts index b6b9696603..7093c2556f 100644 --- a/packages/backend/src/models/_.ts +++ b/packages/backend/src/models/_.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder } from 'typeorm'; +import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder, TypeORMError } from 'typeorm'; import { DriverUtils } from 'typeorm/driver/DriverUtils.js'; import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js'; import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js'; @@ -114,19 +114,61 @@ export const miRepository = { this.selectAliasColumnNames(queryBuilder, builder); if (findOptions) { builder.setFindOptions(findOptions); - /* // @ts-expect-error -- protected - builder.findOptions = findOptions; - if (findOptions.relations) { - const relations = Array.isArray(findOptions.relations) ? OrmUtils.propertyPathsToTruthyObject(findOptions.relations) : findOptions.relations; - // @ts-expect-error -- protected - builder.buildRelations(relations, undefined, mainAlias.metadata, mainAlias.name); - } - // @ts-expect-error -- protected - for (const join of builder.joins) { - } - */ - console.log(builder.expressionMap.joinAttributes); + builder.createJoinExpression = function(this: SelectQueryBuilder) { + const joins = this.expressionMap.joinAttributes.map((joinAttr) => { + /* eslint-disable @typescript-eslint/no-non-null-assertion */ + const relation = joinAttr.relation!; + const destinationTableName = joinAttr.tablePath; + const destinationTableAlias = joinAttr.alias.name; + let appendedCondition = joinAttr.condition ? ` AND (${joinAttr.condition})` : ''; + const parentAlias = joinAttr.parentAlias; + if (relation.isManyToOne || relation.isOneToOneOwner) { + // JOIN `category` `category` ON `category`.`id` = `post`.`categoryId` + const condition = relation.joinColumns.map((joinColumn) => `${destinationTableAlias}.${joinColumn.referencedColumn!.propertyPath}=${relation.propertyPath}_${joinColumn.referencedColumn!.propertyPath}`).join(' AND '); + return ` ${joinAttr.direction} JOIN ${this.getTableName(destinationTableName)} ${this.escape(destinationTableAlias)}${ + // @ts-expect-error -- private + this.createTableLockExpression() + } ON ${this.replacePropertyNames(condition + appendedCondition)}`; + } else if (relation.isOneToMany || relation.isOneToOneNotOwner) { + // JOIN `post` `post` ON `post`.`categoryId` = `category`.`id` + const condition = relation.inverseRelation!.joinColumns.map((joinColumn) => { + if (relation.inverseEntityMetadata.tableType === 'entity-child' && relation.inverseEntityMetadata.discriminatorColumn) { + appendedCondition += ` AND ${destinationTableAlias}.${relation.inverseEntityMetadata.discriminatorColumn.databaseName}='${relation.inverseEntityMetadata.discriminatorValue}'`; + } + return `${destinationTableAlias}.${relation.inverseRelation!.propertyPath}.${joinColumn.referencedColumn!.propertyPath}=${parentAlias}_${joinColumn.referencedColumn!.propertyPath}`; + }).join(' AND '); + if (!condition) { + throw new TypeORMError(`Relation ${relation.entityMetadata.name}.${relation.propertyName} does not have join columns.`); + } + return ` ${joinAttr.direction} JOIN ${this.getTableName(destinationTableName)} ${this.escape(destinationTableAlias)}${ + // @ts-expect-error -- private + this.createTableLockExpression() + } ON ${this.replacePropertyNames(condition + appendedCondition)}`; + } else { + // means many-to-many + const junctionTableName = relation.junctionEntityMetadata!.tablePath; + const junctionAlias = joinAttr.junctionAlias; + let junctionCondition = '', destinationCondition = ''; + if (relation.isOwning) { + junctionCondition = relation.joinColumns.map((joinColumn) => `${junctionAlias}.${joinColumn.propertyPath}=${parentAlias}_${joinColumn.referencedColumn!.propertyPath}`).join(' AND '); + destinationCondition = relation.inverseJoinColumns.map((joinColumn) => `${destinationTableAlias}.${joinColumn.referencedColumn!.propertyPath}=${junctionAlias}_${joinColumn.propertyPath}`).join(' AND '); + } else { + junctionCondition = relation.inverseRelation!.inverseJoinColumns.map((joinColumn) => `${junctionAlias}.${joinColumn.propertyPath}=${parentAlias}_${joinColumn.referencedColumn!.propertyPath}`).join(' AND '); + destinationCondition = relation.inverseRelation!.joinColumns.map((joinColumn) => `${destinationTableAlias}.${joinColumn.referencedColumn!.propertyPath}=${junctionAlias}_${joinColumn.propertyPath}`).join(' AND '); + } + return ` ${joinAttr.direction} JOIN ${this.getTableName(junctionTableName)} ${this.escape(junctionAlias)}${ + // @ts-expect-error -- private + this.createTableLockExpression() + } ON ${this.replacePropertyNames(junctionCondition)} ${joinAttr.direction} JOIN ${this.getTableName(destinationTableName)} ${this.escape(destinationTableAlias)}${ + // @ts-expect-error -- private + this.createTableLockExpression() + } ON ${this.replacePropertyNames(destinationCondition + appendedCondition)}`; + } + /* eslint-enable @typescript-eslint/no-non-null-assertion */ + }); + return joins.join(' '); + }; } const [query, parameters] = builder.getQueryAndParameters(); for (let i = 0; i < Math.ceil(query.length / 10000); i++) {