From 7108d980c3471b66a5f9ca7d10671225b08a9eac Mon Sep 17 00:00:00 2001 From: ChoiWheatley Date: Sun, 9 Mar 2025 18:40:50 +0900 Subject: [PATCH 1/2] =?UTF-8?q?refactor(funding.service):=20mapImage?= =?UTF-8?q?=EA=B0=80=20Nested=20Entity=EB=8F=84=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=ED=95=A0=20=EC=88=98=20=EC=9E=88=EA=B5=AC=EB=82=98!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/funding/funding.service.ts | 13 ++----------- src/features/image/image-instance-manager.ts | 13 +++++++------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/features/funding/funding.service.ts b/src/features/funding/funding.service.ts index 6f34127..c31e241 100644 --- a/src/features/funding/funding.service.ts +++ b/src/features/funding/funding.service.ts @@ -226,17 +226,8 @@ export class FundingService { queryBuilder.leftJoinAndSelect('funding.fundUser', 'u'); - // 현재 Nested Entity에는 ImageInstanceManager#mapImage를 사용할 수 없다. - queryBuilder.leftJoinAndMapOne( - 'u.image', - 'image', - 'ui', - ` - (u.defaultImgId IS NOT NULL AND ui.imgId = u.defaultImgId) OR - (u.defaultImgId IS NULL AND ui.subId = u.userId AND ui.imgType = :imgType) - `, - { imgType: ImageType.User }, - ); + // Nested Entity에도 ImageInstanceManager#mapImage를 사용할 수 있넹?? + this.imageManager.mapImage(queryBuilder, 'u'); const fundingPromies: Promise[] = await queryBuilder .getMany() diff --git a/src/features/image/image-instance-manager.ts b/src/features/image/image-instance-manager.ts index ec745d0..456979b 100644 --- a/src/features/image/image-instance-manager.ts +++ b/src/features/image/image-instance-manager.ts @@ -1,9 +1,8 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { IImageId } from 'src/interfaces/image-id.interface'; import { ImageService } from './image.service'; import { Image } from 'src/entities/image.entity'; import { SelectQueryBuilder } from 'typeorm'; -import { T } from 'node_modules/@faker-js/faker/dist/airline-BnpeTvY9.cjs'; import { ImageType } from 'src/enums/image-type.enum'; import { User } from 'src/entities/user.entity'; import { Funding } from 'src/entities/funding.entity'; @@ -36,7 +35,9 @@ export class ImageInstanceManager { * and image.imgType to the proper ImageType. * * @param qb The TypeORM query builder for one of the entities. - * @param alias Optional alias for the entity in the query. + * @param alias 매핑하고 싶은 엔티티의 alias를 명시, e.g. mapImage(fundingQb, 'author') + * 2025-03-09 edit: 네스팅된 엔티티에도 사용가능! mapImage 하기 전에 연관 엔티티와 join을 수행해야 하겠죠? + * * @returns The query builder with the left join mapped to the `image` property. * @see https://orkhan.gitbook.io/typeorm/docs/select-query-builder#joining-and-mapping-functionality * @example @@ -48,11 +49,11 @@ export class ImageInstanceManager { 'comment.isDel = :isDel', { isDel: false }, ) - .leftJoinAndSelect('comment.author', 'author') + .leftJoinAndSelect('comment.author', 'author') // *** funding.comment.'author' .where('funding.fundUuid = :fundUuid', { fundUuid }) .orderBy('comment.regAt', 'DESC'); - // NOTE - 이런 식으로 매핑하고 싶은 엔티티 alias를 붙여주면 됩니다. + // *** NOTE - 이런 식으로 매핑하고 싶은 엔티티 alias를 붙여주면 됩니다. this.imageInstanceManager.mapImage(fundingQb, 'author'); this.imageInstanceManager.mapImage(fundingQb, 'funding'); @@ -65,7 +66,7 @@ export class ImageInstanceManager { .where('author.userId = :userId', { userId: user.userId! }); // NOTE - 또는 아래와 같이 alias를 생략하면 query builder의 main alias가 자동으로 사용됩니다. - this.imageInstanceManager.mapImage(authorQb); + this.imageInstanceManager.mapImage(authorQb); // 'user'가 자동으로 설정. */ mapImage( qb: SelectQueryBuilder, From fb27c362c9202a890bf17da7ed3bd3d15d07bd31 Mon Sep 17 00:00:00 2001 From: ChoiWheatley Date: Sun, 9 Mar 2025 18:43:14 +0900 Subject: [PATCH 2/2] feat(image-instance-manager): Add mapImages, test required --- src/features/image/image-instance-manager.ts | 49 ++++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/features/image/image-instance-manager.ts b/src/features/image/image-instance-manager.ts index 456979b..1dbb206 100644 --- a/src/features/image/image-instance-manager.ts +++ b/src/features/image/image-instance-manager.ts @@ -110,15 +110,46 @@ export class ImageInstanceManager { ); } - mapImages( - queryBuilder: SelectQueryBuilder, - mapToProperty: string, - property: string, - imgType: ImageType, - ): SelectQueryBuilder { - return queryBuilder.leftJoinAndMapOne(mapToProperty, property, 'i', ``, { - imgType, - }); + mapImages( + qb: SelectQueryBuilder, + alias?: string, + ): SelectQueryBuilder { + // Use provided alias or fall back to the query builder's own alias. + const entityAlias = alias || qb.alias; + + // Determine the correct id field and image type by inspecting the query builder's metadata. + let idField: string; + let imgType: ImageType; + const joinedAlias = qb.expressionMap.findAliasByName(entityAlias); + const target = joinedAlias.metadata.target; + + if (target === User) { + idField = 'userId'; + imgType = ImageType.User; + } else if (target === Funding) { + idField = 'fundId'; + imgType = ImageType.Funding; + } else if (target === Gift) { + idField = 'giftId'; + imgType = ImageType.Gift; + } else { + throw new Error(`mapImage does not support entity type: ${target}`); + } + + // Build the left join condition: + // If defaultImgId is set then join on image.imgId; + // otherwise, join on image.subId matching the entity id and image.imgType. + return qb.leftJoinAndMapMany( + `${entityAlias}.image`, // the property to map the result to (e.g. user.image) + 'image', // the Image entity + `${entityAlias}Image`, // alias for the joined image table + ` + (${entityAlias}.defaultImgId IS NOT NULL AND ${entityAlias}Image.imgId = ${entityAlias}.defaultImgId) + OR + (${entityAlias}.defaultImgId IS NULL AND ${entityAlias}Image.subId = ${entityAlias}.${idField} AND ${entityAlias}Image.imgType = :imgType) + `, + { imgType }, + ); } /**