Skip to content

Commit

Permalink
Merge pull request #40 from TEAM-CLIP/feat/9
Browse files Browse the repository at this point in the history
feat : 가게 리스트 조회 API 구현
  • Loading branch information
isprogrammingfun authored Nov 3, 2024
2 parents db12546 + c14c466 commit 06a4c77
Show file tree
Hide file tree
Showing 23 changed files with 526 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.clip.application.store.port.`in`

interface GetStoreUseCase {

fun getAll(query: GetAllQuery): GetAllResponse

data class GetAllQuery(
val userId: String,
val zoneId: String?
)

data class GetAllResponse(
val registeredStore: List<RegisteredStore>,
val unregisteredStore: List<UnregisteredStore>,
)

data class RegisteredStore(
val storeId: String,
val storeName: String,
val storeImgUrl: String,
val favoriteUserCount: Long,
val isFavorited: Boolean,
val storeType: String,
val discountPolicy : List<DiscountPolicy>
)

data class DiscountPolicy(
val discountType: String,
val discountDescription: String
)

data class UnregisteredStore(
val storeId: String,
val storeName: String,
val storeImgUrl: String,
val storeType: String
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.clip.application.store.port.out

import com.clip.domain.common.DomainId
import com.clip.domain.store.entity.StoreCategory

interface StoreCategoryManagementPort {
fun getCategoriesBy(categoryIds: List<DomainId>): List<StoreCategory>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.clip.application.store.port.out

import com.clip.domain.common.DomainId
import com.clip.domain.store.entity.Store

interface StoreManagementPort {
fun getAllStores(zoneId: DomainId?): List<Store>
fun countFavoriteUsersBy(storeIds: List<DomainId>): LinkedHashMap<DomainId, Long>
fun getFavoritedStoreIdsBy(userId: DomainId, storeIds: List<DomainId>): LinkedHashSet<DomainId>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.clip.application.store.service

import com.clip.application.store.port.`in`.GetStoreUseCase
import com.clip.application.store.port.out.StoreCategoryManagementPort
import com.clip.application.store.port.out.StoreManagementPort
import com.clip.domain.common.DomainId
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional(readOnly = true)
class StoreQueryService(
private val storeManagementPort: StoreManagementPort,
private val storeCategoryManagementPort: StoreCategoryManagementPort
) : GetStoreUseCase{

override fun getAll(query: GetStoreUseCase.GetAllQuery): GetStoreUseCase.GetAllResponse {
val stores = storeManagementPort.getAllStores(query.zoneId?.let { DomainId(it) })
val storeIds = stores.map { it.id }

val favoriteCountsMap = storeManagementPort.countFavoriteUsersBy(storeIds)
val userFavoritedStoreIds = storeManagementPort.getFavoritedStoreIdsBy(DomainId(query.userId), storeIds)

val categories = storeCategoryManagementPort.getCategoriesBy(stores.map { it.storeCategory.categoryId })
val categoryMap = categories.associateBy { it.id }

return GetStoreUseCase.GetAllResponse(
registeredStore = stores.filter { it.storeInfo.isRegistered }.map { store ->
with(store) {
GetStoreUseCase.RegisteredStore(
storeId = id.value,
storeName = storeInfo.name,
storeImgUrl = storeInfo.imgUrl,
favoriteUserCount = favoriteCountsMap[id] ?: 0,
isFavorited = userFavoritedStoreIds.contains(id),
storeType = categoryMap.getValue(storeCategory.categoryId).type.name,
discountPolicy = discount.map {
GetStoreUseCase.DiscountPolicy(
discountType = it.discountPolicyMethod.name,
discountDescription = it.title
)
}
)
}
},
unregisteredStore = stores.filterNot { it.storeInfo.isRegistered }.map { store ->
with(store) {
GetStoreUseCase.UnregisteredStore(
storeId = id.value,
storeName = storeInfo.name,
storeImgUrl = storeInfo.imgUrl,
storeType = categoryMap.getValue(storeCategory.categoryId).type.name,
)
}
}
)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
package com.clip.api.store.api

import com.clip.api.common.security.annotation.AccessUser
import com.clip.api.store.dto.GetAllStoreResponse
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam

@Tag(name = "Store", description = "Store API")
@RequestMapping("/api/v1/stores")
interface StoreApi {

@Operation(summary = "가게 목록 조회")
@GetMapping
@ApiResponse
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "전체 가게 목록 조회 성공",
content = [
Content(
mediaType = "application/json",
schema = Schema(implementation = GetAllStoreResponse::class),
),
],
),
],
)
fun getSpaces(
@AccessUser userId: String,
@RequestParam(value = "region") region: String?
): GetAllStoreResponse






}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.clip.api.store.controller

import com.clip.api.store.api.StoreApi
import com.clip.api.store.dto.GetAllStoreResponse
import com.clip.api.store.dto.GetAllStoreResponse.UnregisteredStoreResponse
import com.clip.api.store.dto.GetAllStoreResponse.RegisteredStoreResponse
import com.clip.application.store.port.`in`.GetStoreUseCase
import org.springframework.web.bind.annotation.RestController

@RestController
class StoreController(
private val getStoreUseCase: GetStoreUseCase
) : StoreApi {

override fun getSpaces(userId: String, zoneId: String?): GetAllStoreResponse {
val response = getStoreUseCase.getAll(
GetStoreUseCase.GetAllQuery(userId, zoneId)
)
return GetAllStoreResponse(
response.registeredStore.map { registeredStore ->
RegisteredStoreResponse(
registeredStore.storeId,
registeredStore.storeName,
registeredStore.storeImgUrl,
registeredStore.favoriteUserCount,
registeredStore.isFavorited,
registeredStore.storeType,
registeredStore.discountPolicy.map {
RegisteredStoreResponse.DiscountPolicyResponse(
it.discountType,
it.discountDescription
)
}
)
},
response.unregisteredStore.map {
UnregisteredStoreResponse(
it.storeId,
it.storeName,
it.storeImgUrl,
it.storeType
)
}

)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.clip.api.store.dto

import io.swagger.v3.oas.annotations.media.Schema

@Schema(description = "가게 리스트 확인 응답")
data class GetAllStoreResponse(
@Schema(description = "입점된 가게 리스트")
val registered: List<RegisteredStoreResponse> = emptyList(),
@Schema(description = "미입점 가게 리스트")
val unregistered: List<UnregisteredStoreResponse> = emptyList()
) {
@Schema(description = "입점된 가게 정보")
data class RegisteredStoreResponse(
@Schema(description = "가게 ID")
val storeId: String,
@Schema(description = "가게 이름")
val storeName: String,
@Schema(description = "가게 이미지 URL")
val storeImgUrl: String,
@Schema(description = "가게 단골 수")
val favoriteUserCount: Long,
@Schema(description = "가게 단골 지정 여부")
val isFavorited: Boolean,
@Schema(description = "가게 타입")
val storeType: String,
@Schema(description = "할인 정책")
val discountPolicy: List<DiscountPolicyResponse> = emptyList()
) {
@Schema(description = "할인 정책")
data class DiscountPolicyResponse(
@Schema(description = "할인 타입")
val discountType: String?,
@Schema(description = "할인 설명")
val discountDescription: String?
)
}

@Schema(description = "입점된 가게 정보")
data class UnregisteredStoreResponse(
@Schema(description = "가게 ID")
val storeId: String,
@Schema(description = "가게 이름")
val storeName: String,
@Schema(description = "가게 이미지 URL")
val storeImgUrl: String,
@Schema(description = "가게 타입")
val storeType: String
) {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.clip.domain.common

abstract class Aggregate<T : Aggregate<T>>(
val id: DomainId,
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.clip.domain.store.entity

import com.clip.domain.common.Aggregate
import com.clip.domain.common.DomainId
import com.clip.domain.store.vo.StoreCategoryInfo
import com.clip.domain.store.vo.DiscountInfo
import com.clip.domain.store.vo.StoreInfo

class Store(
id: DomainId,
val storeInfo: StoreInfo,
val storeCategory: StoreCategoryInfo,
val discount : List<DiscountInfo>
) : Aggregate<Store>(id) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.clip.domain.store.entity

import com.clip.domain.common.Aggregate
import com.clip.domain.common.DomainId
import com.clip.domain.store.enums.Storetype

class StoreCategory(
id : DomainId,
val type : Storetype
) : Aggregate<StoreCategory>(id) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.clip.domain.store.vo

import com.clip.domain.common.DomainId
import com.clip.domain.store.enums.DiscountPolicyMethod

data class DiscountInfo(
val discountId: DomainId,
val discountPolicyMethod: DiscountPolicyMethod,
val title: String,
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.clip.domain.store.vo

import com.clip.domain.common.DomainId

data class StoreCategoryInfo(val categoryId: DomainId) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.clip.domain.store.vo

data class StoreInfo(
val name: String,
val imgUrl: String,
val introduction: String?,
val isRegistered: Boolean,
val storePlace: StorePlace,
) {
data class StorePlace(
val longitude: Double,
val latitude: Double,
) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.clip.persistence.jpa.store

import com.clip.domain.common.DomainId
import com.clip.domain.store.entity.StoreCategory
import com.clip.persistence.jpa.store.entity.StoreCategoryEntity

object StoreCategoryMapper {
fun toStoreCategory(storeCategoryEntity: StoreCategoryEntity): StoreCategory {
return StoreCategory(
id = DomainId(storeCategoryEntity.id),
type = storeCategoryEntity.type
)
}
}
Loading

0 comments on commit 06a4c77

Please sign in to comment.