diff --git a/store/src/main/java/com/ktds/hi/store/biz/usecase/out/StoreRepositoryPort.java b/store/src/main/java/com/ktds/hi/store/biz/usecase/out/StoreRepositoryPort.java index 274d838..04c4901 100644 --- a/store/src/main/java/com/ktds/hi/store/biz/usecase/out/StoreRepositoryPort.java +++ b/store/src/main/java/com/ktds/hi/store/biz/usecase/out/StoreRepositoryPort.java @@ -1,6 +1,7 @@ package com.ktds.hi.store.biz.usecase.out; import com.ktds.hi.store.domain.Store; +import com.ktds.hi.store.infra.gateway.entity.TagEntity; import java.util.List; import java.util.Optional; @@ -14,6 +15,15 @@ import java.util.Optional; */ public interface StoreRepositoryPort { + /** + * 매장의 태그 목록 조회 + */ + List findTagsByStoreId(Long storeId); + + /** + * 여러 매장의 태그 목록 조회 + */ + List findTagsByStoreIds(List storeIds); /** * 태그로 매장 검색 (OR 조건) */ diff --git a/store/src/main/java/com/ktds/hi/store/infra/gateway/StoreRepositoryAdapter.java b/store/src/main/java/com/ktds/hi/store/infra/gateway/StoreRepositoryAdapter.java index b3cb313..8044dc2 100644 --- a/store/src/main/java/com/ktds/hi/store/infra/gateway/StoreRepositoryAdapter.java +++ b/store/src/main/java/com/ktds/hi/store/infra/gateway/StoreRepositoryAdapter.java @@ -5,12 +5,15 @@ import com.ktds.hi.store.domain.StoreStatus; import com.ktds.hi.store.biz.usecase.out.StoreRepositoryPort; import com.ktds.hi.store.biz.usecase.out.StoreSearchCriteria; import com.ktds.hi.store.infra.gateway.entity.StoreEntity; +import com.ktds.hi.store.infra.gateway.entity.TagEntity; import com.ktds.hi.store.infra.gateway.repository.StoreJpaRepository; +import com.ktds.hi.store.infra.gateway.repository.TagJpaRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Component; +import com.ktds.hi.store.infra.gateway.entity.TagEntity; import java.util.Arrays; import java.util.List; @@ -29,7 +32,36 @@ import java.util.stream.Collectors; public class StoreRepositoryAdapter implements StoreRepositoryPort { private final StoreJpaRepository storeJpaRepository; + private final TagJpaRepository tagJpaRepository; + + @Override + public List findTagsByStoreId(Long storeId) { + return tagJpaRepository.findByStoreId(storeId) + .stream() + .map(this::tagToDomain) + .collect(Collectors.toList()); + } + + @Override + public List findTagsByStoreIds(List storeIds) { + return tagJpaRepository.findByStoreIds(storeIds) + .stream() + .map(this::tagToDomain) + .collect(Collectors.toList()); + } + + private TagEntity tagToDomain(TagEntity entity) { + return TagEntity.builder() + .id(entity.getId()) + .tagName(entity.getTagName()) + .tagCategory(entity.getTagCategory()) + .tagColor(entity.getTagColor()) + .sortOrder(entity.getSortOrder()) + .isActive(entity.getIsActive()) + .clickCount(entity.getClickCount()) + .build(); + } @Override public List findStoresByOwnerId(Long ownerId) { return storeJpaRepository.findByOwnerId(ownerId) diff --git a/store/src/main/java/com/ktds/hi/store/infra/gateway/entity/StoreEntity.java b/store/src/main/java/com/ktds/hi/store/infra/gateway/entity/StoreEntity.java index 9171ee1..d8451e9 100644 --- a/store/src/main/java/com/ktds/hi/store/infra/gateway/entity/StoreEntity.java +++ b/store/src/main/java/com/ktds/hi/store/infra/gateway/entity/StoreEntity.java @@ -8,7 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; - +import java.util.HashSet; +import java.util.Set; import java.time.LocalDateTime; /** @@ -76,6 +77,14 @@ public class StoreEntity { @Column(name = "image_url", length = 500) private String imageUrl; + @ManyToMany + @JoinTable( + name = "store_tags", + joinColumns = @JoinColumn(name = "store_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id") + ) + private Set tags = new HashSet<>(); + @CreatedDate @Column(name = "created_at", updatable = false) private LocalDateTime createdAt; diff --git a/store/src/main/java/com/ktds/hi/store/infra/gateway/entity/TagEntity.java b/store/src/main/java/com/ktds/hi/store/infra/gateway/entity/TagEntity.java index 3e48973..1bda7cd 100644 --- a/store/src/main/java/com/ktds/hi/store/infra/gateway/entity/TagEntity.java +++ b/store/src/main/java/com/ktds/hi/store/infra/gateway/entity/TagEntity.java @@ -3,6 +3,11 @@ package com.ktds.hi.store.infra.gateway.entity; import jakarta.persistence.*; import lombok.*; import com.ktds.hi.store.domain.TagCategory; +import com.ktds.hi.store.infra.gateway.entity.StoreEntity; + +import java.util.HashSet; +import java.util.Set; + /** * 태그 엔티티 클래스 * 매장 태그 정보를 저장 @@ -22,6 +27,9 @@ public class TagEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @ManyToMany(mappedBy = "tags") + private Set stores = new HashSet<>(); + @Column(name = "tag_name", nullable = false, length = 50) private String tagName; // 매운맛, 깨끗한, 유제품 등 diff --git a/store/src/main/java/com/ktds/hi/store/infra/gateway/repository/TagJpaRepository.java b/store/src/main/java/com/ktds/hi/store/infra/gateway/repository/TagJpaRepository.java index 3bed601..9653d85 100644 --- a/store/src/main/java/com/ktds/hi/store/infra/gateway/repository/TagJpaRepository.java +++ b/store/src/main/java/com/ktds/hi/store/infra/gateway/repository/TagJpaRepository.java @@ -2,6 +2,7 @@ package com.ktds.hi.store.infra.gateway.repository; import com.ktds.hi.store.domain.TagCategory; import com.ktds.hi.store.infra.gateway.entity.TagEntity; +import io.lettuce.core.dynamic.annotation.Param; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -25,6 +26,16 @@ public interface TagJpaRepository extends JpaRepository { */ List findByIsActiveTrueOrderByTagName(); + @Query("SELECT t FROM TagEntity t JOIN t.stores s WHERE s.id = :storeId AND t.isActive = true") + List findByStoreId(@Param("storeId") Long storeId); + + @Query("SELECT t FROM TagEntity t JOIN t.stores s WHERE s.id IN :storeIds AND t.isActive = true") + List findByStoreIds(@Param("storeIds") List storeIds); + + @Query("SELECT t.tagName, COUNT(s) as storeCount FROM TagEntity t " + + "JOIN t.stores s WHERE t.isActive = true " + + "GROUP BY t.tagName ORDER BY storeCount DESC") + List findTopTagsByStoreCount(@Param("limit") int limit); /** * 태그명으로 조회 */