From 4abd67d9536f33f2361b61d7eff117c904195507 Mon Sep 17 00:00:00 2001 From: thguss Date: Thu, 22 Aug 2024 12:04:10 +0900 Subject: [PATCH 1/2] fix: re-architect erd --- .../persistence/entity/PlaceEntity.kt | 11 +----- .../persistence/entity/SchedulePlaceEntity.kt | 38 +++++++++++++++++++ .../persistence/entity/VoteEntity.kt | 6 +-- 3 files changed, 42 insertions(+), 13 deletions(-) create mode 100644 piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/SchedulePlaceEntity.kt diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/PlaceEntity.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/PlaceEntity.kt index b55e8d0e..e21c2c16 100644 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/PlaceEntity.kt +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/PlaceEntity.kt @@ -23,8 +23,6 @@ import org.hibernate.annotations.SQLRestriction class PlaceEntity( @Column(name = "room_uid", nullable = false, updatable = false) val roomUid: UuidTypeId, - @Column(name = "schedule_id", nullable = false, updatable = false) - var scheduleId: LongTypeId, @Column(name = "name", length = 255, nullable = false) var name: String, @Column(name = "url", length = 255) @@ -42,8 +40,6 @@ class PlaceEntity( var origin: Origin, @Column(name = "memo", length = 150) var memo: String?, - @Column(name = "confirmed", nullable = false) - var confirmed: Boolean = false, @Column(name = "review_count", nullable = false) val reviewCount: Int?, @Column(name = "longitude") @@ -53,9 +49,8 @@ class PlaceEntity( @Column(name = "opening_hours") val openingHours: String?, ) : BaseEntity() { - constructor(roomUid: UuidTypeId, scheduleId: LongTypeId, place: Place) : this( + constructor(roomUid: UuidTypeId, place: Place) : this( roomUid = roomUid, - scheduleId = scheduleId, name = place.name, url = place.url, thumbnailLinks = place.thumbnailLinks.contents ?: "", @@ -64,7 +59,6 @@ class PlaceEntity( starGrade = place.starGrade, origin = place.origin, memo = place.memo, - confirmed = place.confirmed, reviewCount = place.reviewCount, longitude = place.longitude, latitude = place.latitude, @@ -75,7 +69,6 @@ class PlaceEntity( return Place( id = LongTypeId(id), roomUid = roomUid, - scheduleId = scheduleId, name = name, url = url, thumbnailLinks = ThumbnailLinks(thumbnailLinks), @@ -84,7 +77,6 @@ class PlaceEntity( starGrade = starGrade, origin = origin, memo = memo, - confirmed = confirmed, reviewCount = reviewCount, longitude = longitude, latitude = latitude, @@ -100,6 +92,5 @@ class PlaceEntity( starGrade = place.starGrade origin = place.origin memo = place.memo - confirmed = place.confirmed } } diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/SchedulePlaceEntity.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/SchedulePlaceEntity.kt new file mode 100644 index 00000000..33d671a0 --- /dev/null +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/SchedulePlaceEntity.kt @@ -0,0 +1,38 @@ +package com.piikii.output.persistence.postgresql.persistence.entity + +import com.piikii.application.domain.generic.LongTypeId +import com.piikii.application.domain.generic.UuidTypeId +import com.piikii.application.domain.place.SchedulePlace +import com.piikii.output.persistence.postgresql.persistence.common.BaseEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Table + +@Entity +@Table(name = "schedule_place", schema = "piikii") +class SchedulePlaceEntity( + @Column(name = "room_uid", nullable = false, updatable = false) + val roomUid: UuidTypeId, + @Column(name = "schedule_id", nullable = false, updatable = false) + var scheduleId: LongTypeId, + @Column(name = "place_id", nullable = false, updatable = false) + var placeId: LongTypeId, + @Column(name = "confirmed", nullable = false) + var confirmed: Boolean = false, +): BaseEntity() { + constructor(schedulePlace: SchedulePlace): this( + roomUid = schedulePlace.roomUid, + scheduleId = schedulePlace.scheduleId, + placeId = schedulePlace.placeId + ) + + fun toDomain(): SchedulePlace { + return SchedulePlace( + id = LongTypeId(id), + roomUid = roomUid, + scheduleId = scheduleId, + placeId = placeId, + confirmed = confirmed, + ) + } +} diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/VoteEntity.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/VoteEntity.kt index a839fb8c..604cc48f 100644 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/VoteEntity.kt +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/VoteEntity.kt @@ -21,7 +21,7 @@ class VoteEntity( @Column(name = "user_uid", nullable = false) val userUid: UuidTypeId, @Column(name = "place_id", nullable = false) - val placeId: LongTypeId, + val schedulePlaceId: LongTypeId, @Enumerated(EnumType.STRING) @Column(name = "result", nullable = false, length = 10) val result: VoteResult, @@ -30,7 +30,7 @@ class VoteEntity( return Vote( id = LongTypeId(this.id), userUid = this.userUid, - placeId = this.placeId, + schedulePlaceId = this.schedulePlaceId, result = this.result, ) } @@ -39,7 +39,7 @@ class VoteEntity( fun from(vote: Vote): VoteEntity { return VoteEntity( userUid = vote.userUid, - placeId = vote.placeId, + schedulePlaceId = vote.schedulePlaceId, result = vote.result, ) } From 5c2c615f452dd731f0ccc1e4f206858a91c2e22a Mon Sep 17 00:00:00 2001 From: thguss Date: Thu, 22 Aug 2024 15:02:38 +0900 Subject: [PATCH 2/2] fix: updated base on refactored erd --- .../domain/course/CourseService.kt | 111 +++++++----- .../piikii/application/domain/place/Place.kt | 6 - .../application/domain/place/PlaceService.kt | 65 ++++--- .../application/domain/place/SchedulePlace.kt | 16 ++ .../piikii/application/domain/vote/Vote.kt | 2 +- .../application/domain/vote/VoteService.kt | 45 +++-- .../port/input/dto/request/PlaceRequest.kt | 6 - .../port/input/dto/request/VoteRequest.kt | 2 +- .../port/input/dto/response/PlaceResponse.kt | 9 +- .../port/input/dto/response/VoteResponse.kt | 9 +- .../port/output/persistence/CoursePort.kt | 9 - .../port/output/persistence/PlacePort.kt | 7 +- .../output/persistence/SchedulePlacePort.kt | 45 +++++ .../port/output/persistence/VotePort.kt | 4 +- .../domain/course/CourseServiceTest.kt | 68 +++++-- .../domain/fixture/PlaceFixture.kt | 14 -- .../domain/fixture/SchedulePlaceFixture.kt | 53 ++++++ .../application/domain/fixture/VoteFixture.kt | 6 +- .../domain/vote/VoteServiceTest.kt | 171 ++++++++++++++---- .../postgresql/adapter/CourseAdapter.kt | 13 -- .../postgresql/adapter/PlaceAdapter.kt | 29 +-- .../postgresql/adapter/ScheduleAdapter.kt | 8 +- .../adapter/SchedulePlaceAdapter.kt | 94 ++++++++++ .../postgresql/adapter/VoteAdapter.kt | 8 +- .../persistence/entity/SchedulePlaceEntity.kt | 12 +- .../persistence/repository/PlaceRepository.kt | 7 +- .../repository/SchedulePlaceRepository.kt | 45 +++++ .../persistence/repository/VoteRepository.kt | 2 +- .../postgresql/adapter/VoteAdapterTest.kt | 12 +- 29 files changed, 632 insertions(+), 246 deletions(-) create mode 100644 piikii-application/src/main/kotlin/com/piikii/application/domain/place/SchedulePlace.kt delete mode 100644 piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/CoursePort.kt create mode 100644 piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/SchedulePlacePort.kt create mode 100644 piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/SchedulePlaceFixture.kt delete mode 100644 piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/CourseAdapter.kt create mode 100644 piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/SchedulePlaceAdapter.kt create mode 100644 piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/SchedulePlaceRepository.kt diff --git a/piikii-application/src/main/kotlin/com/piikii/application/domain/course/CourseService.kt b/piikii-application/src/main/kotlin/com/piikii/application/domain/course/CourseService.kt index c4c3ccb4..7f96ecad 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/domain/course/CourseService.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/domain/course/CourseService.kt @@ -3,13 +3,14 @@ package com.piikii.application.domain.course import com.piikii.application.domain.generic.LongTypeId import com.piikii.application.domain.generic.UuidTypeId import com.piikii.application.domain.place.Place +import com.piikii.application.domain.place.SchedulePlace import com.piikii.application.domain.schedule.Schedule import com.piikii.application.port.input.CourseUseCase import com.piikii.application.port.input.dto.response.CourseResponse -import com.piikii.application.port.output.persistence.CourseQueryPort -import com.piikii.application.port.output.persistence.PlaceCommandPort import com.piikii.application.port.output.persistence.PlaceQueryPort import com.piikii.application.port.output.persistence.RoomQueryPort +import com.piikii.application.port.output.persistence.SchedulePlaceCommandPort +import com.piikii.application.port.output.persistence.SchedulePlaceQueryPort import com.piikii.application.port.output.persistence.ScheduleQueryPort import com.piikii.application.port.output.persistence.VoteQueryPort import com.piikii.application.port.output.web.NavigationPort @@ -21,16 +22,18 @@ import org.springframework.transaction.annotation.Transactional @Service @Transactional(readOnly = true) class CourseService( - private val courseQueryPort: CourseQueryPort, private val roomQueryPort: RoomQueryPort, private val scheduleQueryPort: ScheduleQueryPort, private val placeQueryPort: PlaceQueryPort, - private val placeCommandPort: PlaceCommandPort, + private val schedulePlaceQueryPort: SchedulePlaceQueryPort, + private val schedulePlaceCommandPort: SchedulePlaceCommandPort, private val voteQueryPort: VoteQueryPort, private val navigationPort: NavigationPort, ) : CourseUseCase { override fun isCourseExist(roomUid: UuidTypeId): Boolean { - return courseQueryPort.isCourseExist(roomUid) + val scheduleIds = scheduleQueryPort.findAllByRoomUid(roomUid) + val confirmedSchedulePlaces = schedulePlaceQueryPort.findAllConfirmedByRoomId(roomUid) + return scheduleIds.size == confirmedSchedulePlaces.size } @Transactional @@ -45,15 +48,16 @@ class CourseService( } val schedules = scheduleQueryPort.findAllByRoomUid(roomUid) - val places = placeQueryPort.findAllByRoomUid(roomUid) + val placeById = placeQueryPort.findAllByRoomUid(roomUid).associateBy { it.id } + val schedulePlaces = schedulePlaceQueryPort.findAllByRoomUid(roomUid) - val placeIds = places.map { it.id } - val votes = voteQueryPort.findAllByPlaceIds(placeIds) - val agreeCountByPlaceId = voteQueryPort.findAgreeCountByPlaceId(votes) + val schedulePlaceIds = schedulePlaces.map { it.id } + val votes = voteQueryPort.findAllBySchedulePlaceIds(schedulePlaceIds) + val agreeCountBySchedulePlaceId = voteQueryPort.findAgreeCountBySchedulePlaceId(votes) return CourseResponse.from( room = room, - placeBySchedule = getPlaceBySchedule(schedules, places, agreeCountByPlaceId), + placeBySchedule = getPlaceBySchedule(schedules, placeById, schedulePlaces, agreeCountBySchedulePlaceId), ) } @@ -62,33 +66,36 @@ class CourseService( roomUid: UuidTypeId, placeId: LongTypeId, ) { - val place = placeQueryPort.findByPlaceId(placeId) + val schedulePlace = schedulePlaceQueryPort.findById(placeId) - if (place.isInvalidRoomUid(roomUid)) { + if (schedulePlace.isInvalidRoomUid(roomUid)) { throw PiikiiException( exceptionCode = ExceptionCode.ILLEGAL_ARGUMENT_EXCEPTION, - detailMessage = "Room UUID: $roomUid, Room UUID in Place: ${place.roomUid}", + detailMessage = "Room UUID: $roomUid, Room UUID in Place: ${schedulePlace.roomUid}", ) } - placeQueryPort.findConfirmedByScheduleId(place.scheduleId)?.let { confirmedPlace -> - placeCommandPort.update(confirmedPlace.id, confirmedPlace.copy(confirmed = false)) + schedulePlaceQueryPort.findConfirmedByScheduleId(schedulePlace.scheduleId)?.let { confirmedPlace -> + schedulePlaceCommandPort.update(confirmedPlace.id, confirmedPlace.copy(confirmed = false)) } - placeCommandPort.update(place.id, place.copy(confirmed = true)) + + schedulePlaceCommandPort.update(placeId, schedulePlace.copy(confirmed = true)) } private fun getPlaceBySchedule( schedules: List, - places: List, - agreeCountByPlaceId: Map, + placeById: Map, + schedulePlaces: List, + agreeCountBySchedulePlaceId: Map, ): Map { // initial 값 설정: null과 빈 Map의 쌍으로 초기화 val initial: Map = emptyMap() - return mapPlacesBySchedule(schedules, places) - .entries.fold(initial) { prePlaceBySchedule, (schedule, places) -> + return mapPlacesBySchedule(schedules, schedulePlaces) + .entries.fold(initial) { prePlaceBySchedule, (schedule, schedulePlacesIn) -> // 현재 CoursePlace 생성 - val confirmedPlace = getConfirmedPlace(schedule, places, agreeCountByPlaceId) + val confirmedPlace = + getConfirmedPlace(schedule, placeById, schedulePlacesIn, agreeCountBySchedulePlaceId) if (confirmedPlace != null) { val preCoursePlace = prePlaceBySchedule.values.lastOrNull() @@ -105,11 +112,12 @@ class CourseService( private fun mapPlacesBySchedule( schedules: List, - places: List, - ): Map> { - val placesByScheduleId = places.groupBy { it.scheduleId } + schedulePlaces: List, + ): Map> { + val schedulePlaceByScheduleId = schedulePlaces.groupBy { it.scheduleId } + return schedules.associateWith { schedule -> - placesByScheduleId[schedule.id] + schedulePlaceByScheduleId[schedule.id] ?: throw PiikiiException( exceptionCode = ExceptionCode.ILLEGAL_ARGUMENT_EXCEPTION, detailMessage = "$EMPTY_CONFIRMED_PLACE Schedule ID: ${schedule.id}", @@ -139,10 +147,11 @@ class CourseService( private fun getConfirmedPlace( schedule: Schedule, - places: List, - agreeCountByPlaceId: Map, + placeById: Map, + schedulePlaces: List, + agreeCountBySchedulePlaceId: Map, ): Place? { - val confirmedPlaces = places.filter { it.confirmed } + val confirmedPlaces = schedulePlaces.filter { it.confirmed } if (confirmedPlaces.size > 1) { throw PiikiiException( @@ -151,27 +160,41 @@ class CourseService( ) } - return confirmedPlaces.firstOrNull() ?: confirmPlace(places, agreeCountByPlaceId) + return confirmedPlaces.firstOrNull() + ?.let { findPlaceInPlaceById(it.placeId, placeById) } + ?: confirmSchedulePlace(schedulePlaces, agreeCountBySchedulePlaceId) + ?.let { findPlaceInPlaceById(it.placeId, placeById) } } - private fun confirmPlace( - places: List, - agreeCountByPlaceId: Map, - ): Place? { - return places - .mapNotNull { place -> - // place.id에 해당하는 agree count가 존재하면 place와 count를 페어로 매핑 - agreeCountByPlaceId[place.id.getValue()]?.let { count -> place to count } + private fun findPlaceInPlaceById( + targetPlaceId: LongTypeId, + placeById: Map, + ): Place { + return placeById[targetPlaceId] + ?: throw PiikiiException( + exceptionCode = ExceptionCode.NOT_FOUNDED, + detailMessage = "Place not found for Place ID: $targetPlaceId", + ) + } + + private fun confirmSchedulePlace( + schedulePlaces: List, + agreeCountBySchedulePlaceId: Map, + ): SchedulePlace? { + return schedulePlaces + .mapNotNull { schedulePlace -> + // place.id에 해당하는 agree count가 존재하면 schedulePlace와 count를 페어로 매핑 + agreeCountBySchedulePlaceId[schedulePlace.id.getValue()]?.let { count -> schedulePlace to count } } - // agree count 내림차순 정렬, (count 동일)place.id 오름차순 정렬 + // agree count 내림차순 정렬, (count 동일)schedulePlace.id 오름차순 정렬 .maxWithOrNull(compareBy({ it.second }, { -it.first.id.getValue() })) - ?.let { (selectedPlace, _) -> - // 최다 찬성 득표 수 place: confirmed 상태로 변경 - placeCommandPort.update( - targetPlaceId = selectedPlace.id, - place = selectedPlace.copy(confirmed = true), + ?.let { (selectedSchedulePlace, _) -> + // 최다 찬성 득표 수 schedulePlace: confirmed 상태로 변경 + schedulePlaceCommandPort.update( + targetId = selectedSchedulePlace.id, + schedulePlace = selectedSchedulePlace.copy(confirmed = true), ) - selectedPlace + selectedSchedulePlace } } diff --git a/piikii-application/src/main/kotlin/com/piikii/application/domain/place/Place.kt b/piikii-application/src/main/kotlin/com/piikii/application/domain/place/Place.kt index 2700314e..96b87c12 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/domain/place/Place.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/domain/place/Place.kt @@ -8,7 +8,6 @@ import com.piikii.application.domain.generic.UuidTypeId data class Place( val id: LongTypeId, val roomUid: UuidTypeId, - val scheduleId: LongTypeId, val name: String, val url: String?, val thumbnailLinks: ThumbnailLinks, @@ -17,7 +16,6 @@ data class Place( val starGrade: Float?, val origin: Origin, val memo: String?, - val confirmed: Boolean, val reviewCount: Int?, val longitude: Double?, val latitude: Double?, @@ -26,8 +24,4 @@ data class Place( fun getCoordinate(): Coordinate { return Coordinate(this.longitude, this.latitude) } - - fun isInvalidRoomUid(roomUid: UuidTypeId): Boolean { - return this.roomUid != roomUid - } } diff --git a/piikii-application/src/main/kotlin/com/piikii/application/domain/place/PlaceService.kt b/piikii-application/src/main/kotlin/com/piikii/application/domain/place/PlaceService.kt index 63bceb81..06b67e06 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/domain/place/PlaceService.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/domain/place/PlaceService.kt @@ -12,6 +12,8 @@ import com.piikii.application.port.output.objectstorage.ObjectStoragePort import com.piikii.application.port.output.persistence.PlaceCommandPort import com.piikii.application.port.output.persistence.PlaceQueryPort import com.piikii.application.port.output.persistence.RoomQueryPort +import com.piikii.application.port.output.persistence.SchedulePlaceCommandPort +import com.piikii.application.port.output.persistence.SchedulePlaceQueryPort import com.piikii.application.port.output.persistence.ScheduleQueryPort import com.piikii.common.exception.ExceptionCode import com.piikii.common.exception.PiikiiException @@ -26,6 +28,8 @@ class PlaceService( private val scheduleQueryPort: ScheduleQueryPort, private val placeQueryPort: PlaceQueryPort, private val placeCommandPort: PlaceCommandPort, + private val schedulePlaceQueryPort: SchedulePlaceQueryPort, + private val schedulePlaceCommandPort: SchedulePlaceCommandPort, private val objectStoragePort: ObjectStoragePort, ) : PlaceUseCase { @Transactional @@ -43,33 +47,30 @@ class PlaceService( } ?: listOf() val room = roomQueryPort.findById(targetRoomUid) - val schedules = scheduleQueryPort.findAllByIds(addPlaceRequest.scheduleIds.map(::LongTypeId)) + val place = addPlaceRequest.toDomain(room.roomUid, imageUrls) + val scheduleIds = scheduleQueryPort.findAllByIds(addPlaceRequest.scheduleIds.map(::LongTypeId)).map { it.id } - val places = - schedules.map { schedule -> - addPlaceRequest.toDomain( - roomUid = room.roomUid, - scheduleId = schedule.id, - imageUrls = imageUrls, - ) - } - - return placeCommandPort.saveAll( - roomUid = room.roomUid, - scheduleIds = schedules.map { it.id }, - places = places, - ).map(::PlaceResponse) + return placeCommandPort.save(room.roomUid, scheduleIds, place).map { PlaceResponse(it, place) } } override fun findAllByRoomUidGroupByPlaceType(roomUid: UuidTypeId): List { + val schedulePlaces = schedulePlaceQueryPort.findAllByRoomUid(roomUid) val scheduleById = scheduleQueryPort.findAllByRoomUid(roomUid).associateBy { it.id } - return placeQueryPort.findAllByRoomUid(roomUid).groupBy { it.scheduleId } - .map { (scheduleId, places) -> + val placeById = placeQueryPort.findAllByRoomUid(roomUid).associateBy { it.id } + + return schedulePlaces.groupBy { it.scheduleId } + .map { (scheduleId, schedulePlaces) -> val schedule = scheduleById[scheduleId] ?: throw PiikiiException(ExceptionCode.NOT_FOUNDED) ScheduleTypeGroupResponse( scheduleId = scheduleId.getValue(), scheduleName = schedule.name, - places = places.map { place -> PlaceResponse(place = place) }, + places = + schedulePlaces.map { schedulePlace -> + val place = + placeById[schedulePlace.placeId] + ?: throw PiikiiException(ExceptionCode.NOT_FOUNDED) + PlaceResponse(schedulePlace, place) + }, ) } } @@ -90,28 +91,34 @@ class PlaceService( ).get() } ?: listOf() - val place = isPlaceNullOrGet(targetPlaceId) - return PlaceResponse( + val schedulePlace = schedulePlaceQueryPort.findById(targetPlaceId) + val place = isPlaceNullOrGet(schedulePlace.placeId) + + val updatedPlace = placeCommandPort.update( - targetPlaceId = targetPlaceId, + targetPlaceId = schedulePlace.placeId, place = modifyPlaceRequest.toDomain( - targetPlaceId, - targetRoomUid, - LongTypeId(modifyPlaceRequest.scheduleId), - filterDuplicateUrls(updatedUrls, place), + targetPlaceId = schedulePlace.placeId, + roomUid = targetRoomUid, + updatedUrls = filterDuplicateUrls(updatedUrls, place), ), - ), - ) + ) + + return PlaceResponse(schedulePlace, updatedPlace) } @Transactional override fun delete(targetPlaceId: LongTypeId) { + val schedulePlace = schedulePlaceQueryPort.findById(targetPlaceId) + val place = isPlaceNullOrGet(schedulePlace.placeId) + objectStoragePort.deleteAllByUrls( bucketFolderType = BUCKET_TYPE, - deleteTargetUrls = isPlaceNullOrGet(targetPlaceId).thumbnailLinks.convertToList, + deleteTargetUrls = place.thumbnailLinks.convertToList, ) - placeCommandPort.delete(targetPlaceId) + schedulePlaceCommandPort.deleteAllByPlaceId(place.id) + placeCommandPort.delete(place.id) } private fun isPlaceNullOrGet(targetPlaceId: LongTypeId): Place { diff --git a/piikii-application/src/main/kotlin/com/piikii/application/domain/place/SchedulePlace.kt b/piikii-application/src/main/kotlin/com/piikii/application/domain/place/SchedulePlace.kt new file mode 100644 index 00000000..0f530d0d --- /dev/null +++ b/piikii-application/src/main/kotlin/com/piikii/application/domain/place/SchedulePlace.kt @@ -0,0 +1,16 @@ +package com.piikii.application.domain.place + +import com.piikii.application.domain.generic.LongTypeId +import com.piikii.application.domain.generic.UuidTypeId + +data class SchedulePlace( + val id: LongTypeId, + val roomUid: UuidTypeId, + val scheduleId: LongTypeId, + val placeId: LongTypeId, + var confirmed: Boolean, +) { + fun isInvalidRoomUid(roomUid: UuidTypeId): Boolean { + return this.roomUid != roomUid + } +} diff --git a/piikii-application/src/main/kotlin/com/piikii/application/domain/vote/Vote.kt b/piikii-application/src/main/kotlin/com/piikii/application/domain/vote/Vote.kt index 4d5b7859..f193c680 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/domain/vote/Vote.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/domain/vote/Vote.kt @@ -6,7 +6,7 @@ import com.piikii.application.domain.generic.UuidTypeId data class Vote( val id: LongTypeId, val userUid: UuidTypeId, - val placeId: LongTypeId, + val schedulePlaceId: LongTypeId, val result: VoteResult, ) diff --git a/piikii-application/src/main/kotlin/com/piikii/application/domain/vote/VoteService.kt b/piikii-application/src/main/kotlin/com/piikii/application/domain/vote/VoteService.kt index e3ed3c78..84e03249 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/domain/vote/VoteService.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/domain/vote/VoteService.kt @@ -10,6 +10,7 @@ import com.piikii.application.port.input.dto.response.VotedPlaceResponse import com.piikii.application.port.input.dto.response.VotedPlacesResponse import com.piikii.application.port.output.persistence.PlaceQueryPort import com.piikii.application.port.output.persistence.RoomQueryPort +import com.piikii.application.port.output.persistence.SchedulePlaceQueryPort import com.piikii.application.port.output.persistence.ScheduleQueryPort import com.piikii.application.port.output.persistence.VoteCommandPort import com.piikii.application.port.output.persistence.VoteQueryPort @@ -25,6 +26,7 @@ class VoteService( private val roomQueryPort: RoomQueryPort, private val placeQueryPort: PlaceQueryPort, private val scheduleQueryPort: ScheduleQueryPort, + private val schedulePlaceQueryPort: SchedulePlaceQueryPort, ) : VoteUseCase { override fun vote( roomUid: UuidTypeId, @@ -38,8 +40,9 @@ class VoteService( ) } - val placeIds = votes.map { it.placeId } - val placesOfRoom = placeQueryPort.findAllByPlaceIds(placeIds).filter { it.roomUid == roomUid } + val schedulePlaceIds = votes.map { it.schedulePlaceId } + + val placesOfRoom = schedulePlaceQueryPort.findAllByIdIn(schedulePlaceIds).filter { it.roomUid == roomUid } require(placesOfRoom.count() == votes.size) { throw PiikiiException(exceptionCode = ExceptionCode.VOTE_PLACE_ID_INVALID) } @@ -58,23 +61,30 @@ class VoteService( } override fun getVoteResultOfRoom(roomUid: UuidTypeId): VoteResultResponse { - val places = placeQueryPort.findAllByRoomUid(roomUid) + val schedulePlaces = schedulePlaceQueryPort.findAllByRoomUid(roomUid) val scheduleById = scheduleQueryPort.findAllByRoomUid(roomUid).associateBy { it.id } - val placeByScheduleId = places.groupBy { it.scheduleId } - val votesGroupByPlaceId = voteQueryPort.findAllByPlaceIds(places.map { it.id }).groupBy { it.placeId } + val schedulePlaceByScheduleId = schedulePlaces.groupBy { it.scheduleId } + val votesGroupBySchedulePlaceId = + voteQueryPort.findAllBySchedulePlaceIds( + schedulePlaces.map { + it.id + }, + ).groupBy { it.schedulePlaceId } + val placeById = placeQueryPort.findAllByPlaceIds(schedulePlaces.map { it.placeId }).associateBy { it.id } return VoteResultResponse( scheduleById.map { (scheduleId, schedule) -> - val placesOfSchedule = placeByScheduleId[scheduleId] ?: emptyList() + val placesOfSchedule = schedulePlaceByScheduleId[scheduleId] ?: emptyList() val votePlaceResponses = placesOfSchedule.map { val (votesOfPlaceAgreeCount, votesOfPlaceDisagreeCount) = getVoteCount( it.id, - votesGroupByPlaceId, + votesGroupBySchedulePlaceId, ) VotePlaceResponse( - place = it, + schedulePlace = it, + place = placeById[it.placeId]!!, countOfAgree = votesOfPlaceAgreeCount, countOfDisagree = votesOfPlaceDisagreeCount, ) @@ -93,17 +103,24 @@ class VoteService( userUid: UuidTypeId, ): VotedPlacesResponse { val votes = voteQueryPort.findAllByUserUid(userUid) - val placeIdByVote = votes.associateBy { it.placeId } - val votedPlaces = placeQueryPort.findAllByPlaceIds(votes.map { it.placeId }).filter { it.roomUid == roomUid } + val placeIdByVote = votes.associateBy { it.schedulePlaceId } + val votedSchedulePlaces = schedulePlaceQueryPort.findAllByIdIn(votes.map { it.schedulePlaceId }) + val placeById = + placeQueryPort.findAllByPlaceIds( + votedSchedulePlaces.map { + it.placeId + }, + ).filter { it.roomUid == roomUid }.associateBy { it.id } + return VotedPlacesResponse( - votedPlaces.map { place -> + votedSchedulePlaces.map { schedulePlace -> val vote = - placeIdByVote[place.id] + placeIdByVote[schedulePlace.id] ?: throw PiikiiException( exceptionCode = ExceptionCode.ACCESS_DENIED, - detailMessage = "$VOTE_NOT_FOUND (Place ID: ${place.id.getValue()})", + detailMessage = "$VOTE_NOT_FOUND (SchedulePlace ID: ${schedulePlace.id.getValue()})", ) - VotedPlaceResponse(place, vote) + VotedPlaceResponse(schedulePlace, placeById[schedulePlace.placeId]!!, vote) }, ) } diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/PlaceRequest.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/PlaceRequest.kt index 0757b01e..b5b4f1b5 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/PlaceRequest.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/PlaceRequest.kt @@ -56,13 +56,11 @@ data class AddPlaceRequest( ) { fun toDomain( roomUid: UuidTypeId, - scheduleId: LongTypeId, imageUrls: List, ): Place { return Place( id = LongTypeId(0L), roomUid = roomUid, - scheduleId = scheduleId, name = name, url = url, thumbnailLinks = ThumbnailLinks(imageUrls), @@ -71,7 +69,6 @@ data class AddPlaceRequest( starGrade = starGrade, origin = Origin.MANUAL, memo = memo, - confirmed = false, reviewCount = reviewCount, longitude = longitude, latitude = latitude, @@ -128,13 +125,11 @@ data class ModifyPlaceRequest( fun toDomain( targetPlaceId: LongTypeId, roomUid: UuidTypeId, - scheduleId: LongTypeId, updatedUrls: List, ): Place { return Place( id = targetPlaceId, roomUid = roomUid, - scheduleId = scheduleId, name = name, url = url, thumbnailLinks = ThumbnailLinks(updatedUrls), @@ -143,7 +138,6 @@ data class ModifyPlaceRequest( starGrade = starGrade, origin = Origin.MANUAL, memo = memo, - confirmed = false, reviewCount = reviewCount, longitude = longitude, latitude = latitude, diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/VoteRequest.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/VoteRequest.kt index 7c8c537f..599a050d 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/VoteRequest.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/request/VoteRequest.kt @@ -25,7 +25,7 @@ data class VoteSaveRequest( Vote( id = LongTypeId(0L), userUid = UuidTypeId(userUid), - placeId = LongTypeId(it.placeId), + schedulePlaceId = LongTypeId(it.placeId), result = it.voteResult, ) } diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/response/PlaceResponse.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/response/PlaceResponse.kt index 252020c9..f23cd2bd 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/response/PlaceResponse.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/response/PlaceResponse.kt @@ -3,6 +3,7 @@ package com.piikii.application.port.input.dto.response import com.piikii.application.domain.generic.ThumbnailLinks import com.piikii.application.domain.place.Origin import com.piikii.application.domain.place.Place +import com.piikii.application.domain.place.SchedulePlace import io.swagger.v3.oas.annotations.media.Schema import java.util.UUID @@ -40,10 +41,10 @@ data class PlaceResponse( @field:Schema(description = "영업시간", example = "10:00 ~ 17:00") val openingHours: String?, ) { - constructor(place: Place) : this( - id = place.id.getValue(), + constructor(schedulePlace: SchedulePlace, place: Place) : this( + id = schedulePlace.id.getValue(), roomUid = place.roomUid.getValue(), - scheduleId = place.scheduleId.getValue(), + scheduleId = schedulePlace.scheduleId.getValue(), name = place.name, url = place.url, placeImageUrls = place.thumbnailLinks, @@ -52,7 +53,7 @@ data class PlaceResponse( starGrade = place.starGrade, origin = place.origin, memo = place.memo, - confirmed = place.confirmed, + confirmed = schedulePlace.confirmed, reviewCount = place.reviewCount, openingHours = place.openingHours, ) diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/response/VoteResponse.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/response/VoteResponse.kt index 0f456b16..817ea4e5 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/response/VoteResponse.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/port/input/dto/response/VoteResponse.kt @@ -3,6 +3,7 @@ package com.piikii.application.port.input.dto.response import com.piikii.application.domain.generic.ThumbnailLinks import com.piikii.application.domain.place.Origin import com.piikii.application.domain.place.Place +import com.piikii.application.domain.place.SchedulePlace import com.piikii.application.domain.vote.Vote import com.piikii.application.domain.vote.VoteResult import io.swagger.v3.oas.annotations.media.Schema @@ -59,8 +60,8 @@ data class VotePlaceResponse( @field:Schema(description = "총 투표 수", example = "11") val countOfVote: Int, ) { - constructor(place: Place, countOfAgree: Int, countOfDisagree: Int) : this( - placeId = place.id.getValue(), + constructor(schedulePlace: SchedulePlace, place: Place, countOfAgree: Int, countOfDisagree: Int) : this( + placeId = schedulePlace.id.getValue(), name = place.name, url = place.url, thumbnailLinks = place.thumbnailLinks, @@ -107,8 +108,8 @@ data class VotedPlaceResponse( @field:Schema(description = "투표한 상태", example = "AGREE") val voteResult: VoteResult, ) { - constructor(place: Place, vote: Vote) : this( - placeId = place.id.getValue(), + constructor(schedulePlace: SchedulePlace, place: Place, vote: Vote) : this( + placeId = schedulePlace.id.getValue(), name = place.name, url = place.url, thumbnailLinks = place.thumbnailLinks, diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/CoursePort.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/CoursePort.kt deleted file mode 100644 index 9f86a5dc..00000000 --- a/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/CoursePort.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.piikii.application.port.output.persistence - -import com.piikii.application.domain.generic.UuidTypeId - -interface CourseQueryPort { - fun isCourseExist(roomUid: UuidTypeId): Boolean -} - -interface CourseCommandPort diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/PlacePort.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/PlacePort.kt index d6fb41ad..79acfc8d 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/PlacePort.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/PlacePort.kt @@ -3,6 +3,7 @@ package com.piikii.application.port.output.persistence import com.piikii.application.domain.generic.LongTypeId import com.piikii.application.domain.generic.UuidTypeId import com.piikii.application.domain.place.Place +import com.piikii.application.domain.place.SchedulePlace interface PlaceQueryPort { fun findByPlaceId(placeId: LongTypeId): Place @@ -10,16 +11,14 @@ interface PlaceQueryPort { fun findAllByPlaceIds(placeIds: List): List fun findAllByRoomUid(roomUid: UuidTypeId): List - - fun findConfirmedByScheduleId(scheduleId: LongTypeId): Place? } interface PlaceCommandPort { fun save( roomUid: UuidTypeId, - scheduleId: LongTypeId, + scheduleIds: List, place: Place, - ): Place + ): List fun saveAll( roomUid: UuidTypeId, diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/SchedulePlacePort.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/SchedulePlacePort.kt new file mode 100644 index 00000000..481dcc46 --- /dev/null +++ b/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/SchedulePlacePort.kt @@ -0,0 +1,45 @@ +package com.piikii.application.port.output.persistence + +import com.piikii.application.domain.generic.LongTypeId +import com.piikii.application.domain.generic.UuidTypeId +import com.piikii.application.domain.place.SchedulePlace + +interface SchedulePlaceQueryPort { + fun findAllByRoomUid(roomUid: UuidTypeId): List + + fun findAllByPlaceId(placeId: LongTypeId): List + + fun findAllConfirmedByRoomId(roomId: UuidTypeId): List + + fun findByRoomUidAndPlaceId( + roomUid: UuidTypeId, + placeId: LongTypeId, + ): SchedulePlace + + fun findConfirmedByScheduleId(scheduleId: LongTypeId): SchedulePlace? + + fun findAllByRoomUidAndPaceIds( + roomUid: UuidTypeId, + placeIds: List, + ): List + + fun findById(id: LongTypeId): SchedulePlace + + fun findAllByIdIn(ids: List): List +} + +interface SchedulePlaceCommandPort { + fun saveAll(schedulePlaces: List) + + fun deleteAllByPlaceIdAndScheduleIds( + placeId: LongTypeId, + scheduleIds: List, + ) + + fun deleteAllByPlaceId(placeId: LongTypeId) + + fun update( + targetId: LongTypeId, + schedulePlace: SchedulePlace, + ) +} diff --git a/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/VotePort.kt b/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/VotePort.kt index e93ac053..138b1876 100644 --- a/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/VotePort.kt +++ b/piikii-application/src/main/kotlin/com/piikii/application/port/output/persistence/VotePort.kt @@ -5,9 +5,9 @@ import com.piikii.application.domain.generic.UuidTypeId import com.piikii.application.domain.vote.Vote interface VoteQueryPort { - fun findAgreeCountByPlaceId(votes: List): Map + fun findAgreeCountBySchedulePlaceId(votes: List): Map - fun findAllByPlaceIds(placeIds: List): List + fun findAllBySchedulePlaceIds(schedulePlaceIds: List): List fun findAllByUserUid(userUid: UuidTypeId): List } diff --git a/piikii-application/src/test/kotlin/com/piikii/application/domain/course/CourseServiceTest.kt b/piikii-application/src/test/kotlin/com/piikii/application/domain/course/CourseServiceTest.kt index c81306f9..aee29860 100644 --- a/piikii-application/src/test/kotlin/com/piikii/application/domain/course/CourseServiceTest.kt +++ b/piikii-application/src/test/kotlin/com/piikii/application/domain/course/CourseServiceTest.kt @@ -3,12 +3,13 @@ package com.piikii.application.domain.course import com.piikii.application.domain.fixture.PlaceFixture import com.piikii.application.domain.fixture.RoomFixture import com.piikii.application.domain.fixture.ScheduleFixture +import com.piikii.application.domain.fixture.SchedulePlaceFixture import com.piikii.application.domain.fixture.VoteFixture import com.piikii.application.domain.vote.VoteResult -import com.piikii.application.port.output.persistence.CourseQueryPort -import com.piikii.application.port.output.persistence.PlaceCommandPort import com.piikii.application.port.output.persistence.PlaceQueryPort import com.piikii.application.port.output.persistence.RoomQueryPort +import com.piikii.application.port.output.persistence.SchedulePlaceCommandPort +import com.piikii.application.port.output.persistence.SchedulePlaceQueryPort import com.piikii.application.port.output.persistence.ScheduleQueryPort import com.piikii.application.port.output.persistence.VoteQueryPort import com.piikii.application.port.output.web.NavigationPort @@ -39,16 +40,16 @@ class CourseServiceTest { lateinit var placeQueryPort: PlaceQueryPort @Mock - lateinit var placeCommandPort: PlaceCommandPort + lateinit var schedulePlaceQueryPort: SchedulePlaceQueryPort @Mock - lateinit var voteQueryPort: VoteQueryPort + lateinit var schedulePlaceCommandPort: SchedulePlaceCommandPort @Mock - lateinit var navigationPort: NavigationPort + lateinit var voteQueryPort: VoteQueryPort @Mock - lateinit var courseQueryPort: CourseQueryPort + lateinit var navigationPort: NavigationPort @Test fun `VoteDeadline 이 현재보다 이후이면 Exception 이 발생한다`() { @@ -92,27 +93,46 @@ class CourseServiceTest { PlaceFixture.create() .id(1L) .roomUid(room.roomUid) - .scheduleId(schedules[0].id) - .confirmed(true) .longitude(126.9246033) .latitude(33.45241976) .build(), PlaceFixture.create() .id(2L) .roomUid(room.roomUid) - .scheduleId(schedules[1].id) .longitude(126.9246033) .latitude(33.45241976) .build(), PlaceFixture.create() .id(3L) .roomUid(room.roomUid) - .scheduleId(schedules[1].id) .longitude(126.9246033) .latitude(33.45241977) .build(), ) + val schedulePlaces = + listOf( + SchedulePlaceFixture.create() + .id(1L) + .roomUid(room.roomUid) + .scheduleId(schedules[0].id) + .placeId(places[0].id) + .confirmed(true) + .build(), + SchedulePlaceFixture.create() + .id(2L) + .roomUid(room.roomUid) + .scheduleId(schedules[1].id) + .placeId(places[1].id) + .build(), + SchedulePlaceFixture.create() + .id(3L) + .roomUid(room.roomUid) + .scheduleId(schedules[1].id) + .placeId(places[2].id) + .build(), + ) + val votes = listOf( VoteFixture.create().placeId(places[1].id).result(VoteResult.AGREE).build(), @@ -123,8 +143,9 @@ class CourseServiceTest { given(roomQueryPort.findById(room.roomUid)).willReturn(room) given(scheduleQueryPort.findAllByRoomUid(room.roomUid)).willReturn(schedules) given(placeQueryPort.findAllByRoomUid(room.roomUid)).willReturn(places) - given(voteQueryPort.findAllByPlaceIds(anyList())).willReturn(votes) - given(voteQueryPort.findAgreeCountByPlaceId(votes)) + given(schedulePlaceQueryPort.findAllByRoomUid(room.roomUid)).willReturn(schedulePlaces) + given(voteQueryPort.findAllBySchedulePlaceIds(anyList())).willReturn(votes) + given(voteQueryPort.findAgreeCountBySchedulePlaceId(votes)) .willReturn( mapOf( 2L to 1, @@ -137,8 +158,8 @@ class CourseServiceTest { given(navigationPort.getDistance(coordinate1, coordinate2)) .willReturn(Distance(100, 5)) - val updatedPlace = places[2].copy(confirmed = true) - given(placeCommandPort.update(places[2].id, updatedPlace)).willReturn(updatedPlace) + val updatedPlace = schedulePlaces[2].copy(confirmed = true) + given(schedulePlaceCommandPort.update(schedulePlaces[2].id, updatedPlace)).will { } // when val result = courseService.retrieveCourse(room.roomUid) @@ -167,21 +188,36 @@ class CourseServiceTest { PlaceFixture.create() .id(1L) .roomUid(room.roomUid) - .scheduleId(schedules[0].id) - .confirmed(true) .longitude(126.9246033) .latitude(33.45241976) .build(), PlaceFixture.create() + .id(2L) + .roomUid(room.roomUid) + .build(), + ) + + val schedulePlaces = + listOf( + SchedulePlaceFixture.create() + .id(1L) + .roomUid(room.roomUid) + .scheduleId(schedules[0].id) + .placeId(places[0].id) + .confirmed(true) + .build(), + SchedulePlaceFixture.create() .id(2L) .roomUid(room.roomUid) .scheduleId(schedules[1].id) + .placeId(places[0].id) .confirmed(true) .build(), ) given(roomQueryPort.findById(room.roomUid)).willReturn(room) given(scheduleQueryPort.findAllByRoomUid(room.roomUid)).willReturn(schedules) + given(schedulePlaceQueryPort.findAllByRoomUid(room.roomUid)).willReturn(schedulePlaces) given(placeQueryPort.findAllByRoomUid(room.roomUid)).willReturn(places) // when diff --git a/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/PlaceFixture.kt b/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/PlaceFixture.kt index 65cc31a0..fae35e04 100644 --- a/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/PlaceFixture.kt +++ b/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/PlaceFixture.kt @@ -17,9 +17,7 @@ class PlaceFixture( private var starGrade: Float? = null, private var origin: Origin = Origin.MANUAL, private var roomUid: UuidTypeId = UuidTypeId(UUID.randomUUID()), - private var scheduleId: LongTypeId = LongTypeId(0L), private var memo: String? = null, - private var confirmed: Boolean = false, private var reviewCount: Int = 0, private var longitude: Double? = null, private var latitude: Double? = null, @@ -40,16 +38,6 @@ class PlaceFixture( return this } - fun scheduleId(scheduleId: LongTypeId): PlaceFixture { - this.scheduleId = scheduleId - return this - } - - fun confirmed(confirmed: Boolean): PlaceFixture { - this.confirmed = confirmed - return this - } - fun longitude(longitude: Double): PlaceFixture { this.longitude = longitude return this @@ -71,9 +59,7 @@ class PlaceFixture( starGrade = this.starGrade, origin = this.origin, roomUid = this.roomUid, - scheduleId = this.scheduleId, memo = this.memo, - confirmed = this.confirmed, reviewCount = this.reviewCount, longitude = this.longitude, latitude = this.latitude, diff --git a/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/SchedulePlaceFixture.kt b/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/SchedulePlaceFixture.kt new file mode 100644 index 00000000..01ced0bd --- /dev/null +++ b/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/SchedulePlaceFixture.kt @@ -0,0 +1,53 @@ +package com.piikii.application.domain.fixture + +import com.piikii.application.domain.generic.LongTypeId +import com.piikii.application.domain.generic.UuidTypeId +import com.piikii.application.domain.place.SchedulePlace +import java.util.UUID + +class SchedulePlaceFixture( + private var id: LongTypeId = LongTypeId(0L), + private var roomUid: UuidTypeId = UuidTypeId(UUID.randomUUID()), + private var scheduleId: LongTypeId = LongTypeId(0L), + private var placeId: LongTypeId = LongTypeId(0L), + private var confirmed: Boolean = false, +) { + fun id(id: Long): SchedulePlaceFixture { + this.id = LongTypeId(id) + return this + } + + fun roomUid(roomUid: UuidTypeId): SchedulePlaceFixture { + this.roomUid = roomUid + return this + } + + fun scheduleId(scheduleId: LongTypeId): SchedulePlaceFixture { + this.scheduleId = scheduleId + return this + } + + fun placeId(placeId: LongTypeId): SchedulePlaceFixture { + this.placeId = placeId + return this + } + + fun confirmed(confirmed: Boolean): SchedulePlaceFixture { + this.confirmed = confirmed + return this + } + + fun build(): SchedulePlace { + return SchedulePlace( + id = this.id, + roomUid = this.roomUid, + scheduleId = this.scheduleId, + placeId = this.placeId, + confirmed = this.confirmed, + ) + } + + companion object { + fun create() = SchedulePlaceFixture() + } +} diff --git a/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/VoteFixture.kt b/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/VoteFixture.kt index 72f40fd5..50b3eb27 100644 --- a/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/VoteFixture.kt +++ b/piikii-application/src/test/kotlin/com/piikii/application/domain/fixture/VoteFixture.kt @@ -9,11 +9,11 @@ import java.util.UUID class VoteFixture( private var id: LongTypeId = LongTypeId(0L), private var userUid: UuidTypeId = UuidTypeId(UUID.randomUUID()), - private var placeId: LongTypeId = LongTypeId(0L), + private var schedulePlaceId: LongTypeId = LongTypeId(0L), private var result: VoteResult = VoteResult.DISAGREE, ) { fun placeId(placeId: LongTypeId): VoteFixture { - this.placeId = placeId + this.schedulePlaceId = placeId return this } @@ -26,7 +26,7 @@ class VoteFixture( return Vote( id = this.id, userUid = this.userUid, - placeId = this.placeId, + schedulePlaceId = this.schedulePlaceId, result = this.result, ) } diff --git a/piikii-application/src/test/kotlin/com/piikii/application/domain/vote/VoteServiceTest.kt b/piikii-application/src/test/kotlin/com/piikii/application/domain/vote/VoteServiceTest.kt index 23e1c8c5..ea14060d 100644 --- a/piikii-application/src/test/kotlin/com/piikii/application/domain/vote/VoteServiceTest.kt +++ b/piikii-application/src/test/kotlin/com/piikii/application/domain/vote/VoteServiceTest.kt @@ -1,5 +1,6 @@ package com.piikii.application.domain.vote +import com.piikii.application.domain.fixture.SchedulePlaceFixture import com.piikii.application.domain.generic.LongTypeId import com.piikii.application.domain.generic.ThumbnailLinks import com.piikii.application.domain.generic.UuidTypeId @@ -11,6 +12,7 @@ import com.piikii.application.domain.schedule.Schedule import com.piikii.application.domain.schedule.ScheduleType import com.piikii.application.port.output.persistence.PlaceQueryPort import com.piikii.application.port.output.persistence.RoomQueryPort +import com.piikii.application.port.output.persistence.SchedulePlaceQueryPort import com.piikii.application.port.output.persistence.ScheduleQueryPort import com.piikii.application.port.output.persistence.VoteCommandPort import com.piikii.application.port.output.persistence.VoteQueryPort @@ -22,7 +24,6 @@ import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource -import org.mockito.BDDMockito.anyList import org.mockito.BDDMockito.given import org.mockito.BDDMockito.verify import org.mockito.InjectMocks @@ -52,6 +53,9 @@ class VoteServiceTest { @Mock lateinit var scheduleQueryPort: ScheduleQueryPort + @Mock + lateinit var schedulePlaceQueryPort: SchedulePlaceQueryPort + @MethodSource("voteUnavailableRoom") @ParameterizedTest fun `Room Vote가 불가능한 상황에서 vote 요청 시 Exception이 발생한다`(room: Room) { @@ -85,19 +89,19 @@ class VoteServiceTest { Vote( id = LongTypeId(1L), userUid = userUid, - placeId = LongTypeId(1), + schedulePlaceId = LongTypeId(1), result = VoteResult.AGREE, ), Vote( id = LongTypeId(2L), userUid = userUid, - placeId = LongTypeId(2), + schedulePlaceId = LongTypeId(2), result = VoteResult.DISAGREE, ), Vote( id = LongTypeId(3L), userUid = userUid, - placeId = LongTypeId(3), + schedulePlaceId = LongTypeId(3), result = VoteResult.AGREE, ), ) @@ -112,19 +116,24 @@ class VoteServiceTest { starGrade = null, origin = Origin.MANUAL, roomUid = roomUid, - scheduleId = LongTypeId(0L), memo = null, - confirmed = false, reviewCount = 0, longitude = 126.9246033, latitude = 33.45241976, openingHours = "", ) + val schedulePlace = + SchedulePlaceFixture.create() + .roomUid(roomUid) + .scheduleId(LongTypeId(0L)) + .placeId(place.id) + .confirmed(false) + .build() given(roomQueryPort.findById(room.roomUid)) .willReturn(room) - given(placeQueryPort.findAllByPlaceIds(votes.map { it.placeId })) - .willReturn(listOf(place)) + given(schedulePlaceQueryPort.findAllByIdIn(votes.map { it.schedulePlaceId })) + .willReturn(listOf(schedulePlace)) // when & then assertThatThrownBy { voteService.vote(room.roomUid, votes) } @@ -149,8 +158,18 @@ class VoteServiceTest { ) val votes = listOf( - Vote(id = LongTypeId(1L), userUid = userUid, placeId = LongTypeId(1), result = VoteResult.AGREE), - Vote(id = LongTypeId(2L), userUid = userUid, placeId = LongTypeId(2), result = VoteResult.DISAGREE), + Vote( + id = LongTypeId(1L), + userUid = userUid, + schedulePlaceId = LongTypeId(1), + result = VoteResult.AGREE, + ), + Vote( + id = LongTypeId(2L), + userUid = userUid, + schedulePlaceId = LongTypeId(2), + result = VoteResult.DISAGREE, + ), ) val places = listOf( @@ -164,9 +183,7 @@ class VoteServiceTest { starGrade = null, origin = Origin.MANUAL, roomUid = UuidTypeId(UUID.randomUUID()), - scheduleId = LongTypeId(0L), memo = null, - confirmed = false, reviewCount = 0, longitude = 126.9246033, latitude = 33.45241976, @@ -182,20 +199,35 @@ class VoteServiceTest { starGrade = null, origin = Origin.MANUAL, roomUid = UuidTypeId(UUID.randomUUID()), - scheduleId = LongTypeId(0L), memo = null, - confirmed = false, reviewCount = 0, longitude = 126.9246033, latitude = 33.45241976, openingHours = "", ), ) + val schedulePlaces = + listOf( + SchedulePlaceFixture.create() + .id(0L) + .roomUid(places[0].roomUid) + .scheduleId(LongTypeId(0L)) + .placeId(places[0].id) + .confirmed(false) + .build(), + SchedulePlaceFixture.create() + .id(1L) + .roomUid(places[1].roomUid) + .scheduleId(LongTypeId(0L)) + .placeId(places[1].id) + .confirmed(false) + .build(), + ) given(roomQueryPort.findById(room.roomUid)) .willReturn(room) - given(placeQueryPort.findAllByPlaceIds(votes.map { it.placeId })) - .willReturn(places) + given(schedulePlaceQueryPort.findAllByIdIn(votes.map { it.schedulePlaceId })) + .willReturn(schedulePlaces) // when & then assertThatThrownBy { voteService.vote(room.roomUid, votes) } @@ -220,8 +252,18 @@ class VoteServiceTest { ) val votes = listOf( - Vote(id = LongTypeId(1L), userUid = userUid, placeId = LongTypeId(1), result = VoteResult.AGREE), - Vote(id = LongTypeId(2L), userUid = userUid, placeId = LongTypeId(2), result = VoteResult.DISAGREE), + Vote( + id = LongTypeId(1L), + userUid = userUid, + schedulePlaceId = LongTypeId(1), + result = VoteResult.AGREE, + ), + Vote( + id = LongTypeId(2L), + userUid = userUid, + schedulePlaceId = LongTypeId(2), + result = VoteResult.DISAGREE, + ), ) val places = listOf( @@ -235,9 +277,7 @@ class VoteServiceTest { starGrade = null, origin = Origin.MANUAL, roomUid = roomUid, - scheduleId = LongTypeId(0), memo = null, - confirmed = false, reviewCount = 0, longitude = 126.9246033, latitude = 33.45241976, @@ -253,20 +293,35 @@ class VoteServiceTest { starGrade = null, origin = Origin.MANUAL, roomUid = roomUid, - scheduleId = LongTypeId(0), memo = null, - confirmed = false, reviewCount = 0, longitude = 126.9246033, latitude = 33.45241976, openingHours = "", ), ) + val schedulePlaces = + listOf( + SchedulePlaceFixture.create() + .id(1L) + .roomUid(places[0].roomUid) + .scheduleId(LongTypeId(0L)) + .placeId(places[0].id) + .confirmed(false) + .build(), + SchedulePlaceFixture.create() + .id(2L) + .roomUid(places[1].roomUid) + .scheduleId(LongTypeId(0L)) + .placeId(places[1].id) + .confirmed(false) + .build(), + ) given(roomQueryPort.findById(roomUid)) .willReturn(room) - given(placeQueryPort.findAllByPlaceIds(votes.map { it.placeId })) - .willReturn(places) + given(schedulePlaceQueryPort.findAllByIdIn(votes.map { it.schedulePlaceId })) + .willReturn(schedulePlaces) // when & then assertDoesNotThrow { voteService.vote(roomUid, votes) } @@ -281,10 +336,30 @@ class VoteServiceTest { val votes = listOf( - Vote(id = LongTypeId(1L), userUid = userUid, placeId = LongTypeId(1), result = VoteResult.AGREE), - Vote(id = LongTypeId(2L), userUid = userUid, placeId = LongTypeId(3), result = VoteResult.AGREE), - Vote(id = LongTypeId(3L), userUid = userUid, placeId = LongTypeId(3), result = VoteResult.AGREE), - Vote(id = LongTypeId(4L), userUid = userUid, placeId = LongTypeId(2), result = VoteResult.DISAGREE), + Vote( + id = LongTypeId(1L), + userUid = userUid, + schedulePlaceId = LongTypeId(1), + result = VoteResult.AGREE, + ), + Vote( + id = LongTypeId(2L), + userUid = userUid, + schedulePlaceId = LongTypeId(3), + result = VoteResult.AGREE, + ), + Vote( + id = LongTypeId(3L), + userUid = userUid, + schedulePlaceId = LongTypeId(3), + result = VoteResult.AGREE, + ), + Vote( + id = LongTypeId(4L), + userUid = userUid, + schedulePlaceId = LongTypeId(2), + result = VoteResult.DISAGREE, + ), ) val schedules = listOf( @@ -304,9 +379,7 @@ class VoteServiceTest { starGrade = null, origin = Origin.MANUAL, roomUid = roomUid, - scheduleId = LongTypeId(1), memo = null, - confirmed = false, reviewCount = 0, longitude = 126.9246033, latitude = 33.45241976, @@ -322,9 +395,7 @@ class VoteServiceTest { starGrade = null, origin = Origin.MANUAL, roomUid = roomUid, - scheduleId = LongTypeId(2), memo = null, - confirmed = false, reviewCount = 0, longitude = 126.9246033, latitude = 33.45241976, @@ -340,23 +411,49 @@ class VoteServiceTest { starGrade = null, origin = Origin.MANUAL, roomUid = roomUid, - scheduleId = LongTypeId(2), memo = null, - confirmed = false, reviewCount = 0, longitude = 126.9246033, latitude = 33.45241976, openingHours = "", ), ) + val schedulePlaces = + listOf( + SchedulePlaceFixture.create() + .id(1L) + .roomUid(places[0].roomUid) + .scheduleId(LongTypeId(1L)) + .placeId(places[0].id) + .confirmed(false) + .build(), + SchedulePlaceFixture.create() + .id(2L) + .roomUid(places[1].roomUid) + .scheduleId(LongTypeId(2L)) + .placeId(places[1].id) + .confirmed(false) + .build(), + SchedulePlaceFixture.create() + .id(3L) + .roomUid(places[2].roomUid) + .scheduleId(LongTypeId(2L)) + .placeId(places[2].id) + .confirmed(false) + .build(), + ) - given(placeQueryPort.findAllByRoomUid(roomUid)) + given(schedulePlaceQueryPort.findAllByRoomUid(roomUid)) + .willReturn(schedulePlaces) + given(placeQueryPort.findAllByPlaceIds(schedulePlaces.map { it.placeId })) .willReturn(places) given(scheduleQueryPort.findAllByRoomUid(roomUid)) .willReturn(schedules) - given(voteQueryPort.findAllByPlaceIds(anyList())) + given(voteQueryPort.findAllBySchedulePlaceIds(schedulePlaces.map { it.id })) .willReturn(votes) + println(voteService.getVoteResultOfRoom(roomUid)) + // when val voteResultResponse = assertDoesNotThrow { voteService.getVoteResultOfRoom(roomUid) } @@ -367,6 +464,8 @@ class VoteServiceTest { assertThat(scheduleTwoResponse.places).hasSize(2) // 동의 투표 수 기준 내림차순 정렬 여부 확인 + println("===") + println(scheduleTwoResponse.places[0]) assertThat(scheduleTwoResponse.places[0].countOfAgree).isEqualTo(2) } diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/CourseAdapter.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/CourseAdapter.kt deleted file mode 100644 index b8cb65da..00000000 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/CourseAdapter.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.piikii.output.persistence.postgresql.adapter - -import com.piikii.application.domain.generic.UuidTypeId -import com.piikii.application.port.output.persistence.CourseQueryPort -import org.springframework.stereotype.Repository - -@Repository -class CourseAdapter() : CourseQueryPort { - override fun isCourseExist(roomUid: UuidTypeId): Boolean { - // TODO: implement - return false - } -} diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/PlaceAdapter.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/PlaceAdapter.kt index 7ae9d497..f13d1e44 100644 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/PlaceAdapter.kt +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/PlaceAdapter.kt @@ -3,12 +3,15 @@ package com.piikii.output.persistence.postgresql.adapter import com.piikii.application.domain.generic.LongTypeId import com.piikii.application.domain.generic.UuidTypeId import com.piikii.application.domain.place.Place +import com.piikii.application.domain.place.SchedulePlace import com.piikii.application.port.output.persistence.PlaceCommandPort import com.piikii.application.port.output.persistence.PlaceQueryPort import com.piikii.common.exception.ExceptionCode import com.piikii.common.exception.PiikiiException import com.piikii.output.persistence.postgresql.persistence.entity.PlaceEntity +import com.piikii.output.persistence.postgresql.persistence.entity.SchedulePlaceEntity import com.piikii.output.persistence.postgresql.persistence.repository.PlaceRepository +import com.piikii.output.persistence.postgresql.persistence.repository.SchedulePlaceRepository import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Repository import org.springframework.transaction.annotation.Transactional @@ -17,20 +20,18 @@ import org.springframework.transaction.annotation.Transactional @Transactional(readOnly = true) class PlaceAdapter( private val placeRepository: PlaceRepository, + private val schedulePlaceRepository: SchedulePlaceRepository, ) : PlaceQueryPort, PlaceCommandPort { @Transactional override fun save( roomUid: UuidTypeId, - scheduleId: LongTypeId, + scheduleIds: List, place: Place, - ): Place { - val placeEntity = - PlaceEntity( - roomUid = roomUid, - scheduleId = place.id, - place = place, - ) - return placeRepository.save(placeEntity).toDomain() + ): List { + val savedPlaceEntity = placeRepository.save(PlaceEntity(roomUid, place)) + val placeId = LongTypeId(savedPlaceEntity.id) + val schedulePlaceEntities = scheduleIds.map { SchedulePlaceEntity(roomUid, it, placeId) } + return schedulePlaceRepository.saveAll(schedulePlaceEntities).map { it.toDomain() } } override fun saveAll( @@ -42,7 +43,6 @@ class PlaceAdapter( places.map { PlaceEntity( roomUid = roomUid, - scheduleId = it.scheduleId, place = it, ) } @@ -86,13 +86,4 @@ class PlaceAdapter( override fun findAllByRoomUid(roomUid: UuidTypeId): List { return placeRepository.findAllByRoomUid(roomUid).map { it.toDomain() } } - - override fun findConfirmedByScheduleId(scheduleId: LongTypeId): Place? { - val places = placeRepository.findByScheduleIdAndConfirmed(scheduleId.getValue(), true) - return places.singleOrNull()?.toDomain() - ?: throw PiikiiException( - exceptionCode = ExceptionCode.ACCESS_DENIED, - detailMessage = "중복된 장소 코스가 있습니다. 데이터를 확인하세요. Schedule ID : $scheduleId", - ) - } } diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/ScheduleAdapter.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/ScheduleAdapter.kt index bbb90833..eb8b3b70 100644 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/ScheduleAdapter.kt +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/ScheduleAdapter.kt @@ -9,6 +9,7 @@ import com.piikii.common.exception.ExceptionCode import com.piikii.common.exception.PiikiiException import com.piikii.output.persistence.postgresql.persistence.entity.ScheduleEntity import com.piikii.output.persistence.postgresql.persistence.repository.PlaceRepository +import com.piikii.output.persistence.postgresql.persistence.repository.SchedulePlaceRepository import com.piikii.output.persistence.postgresql.persistence.repository.ScheduleRepository import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Repository @@ -19,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional class ScheduleAdapter( private val scheduleRepository: ScheduleRepository, private val placeRepository: PlaceRepository, + private val schedulePlaceRepository: SchedulePlaceRepository, ) : ScheduleCommandPort, ScheduleQueryPort { @Transactional override fun saveSchedules(schedules: List) { @@ -29,7 +31,11 @@ class ScheduleAdapter( @Transactional override fun deleteSchedules(scheduleIds: List) { - placeRepository.deleteByScheduleIdIn(scheduleIds.map { it.getValue() }) + val placeIds = + schedulePlaceRepository.findAllByScheduleIdIn(scheduleIds.map { it.getValue() }) + .map { it.placeId.getValue() } + schedulePlaceRepository.deleteAllByScheduleIdIn(scheduleIds.map { it.getValue() }) + placeRepository.deleteAllByIdIn(placeIds) scheduleRepository.deleteAll( scheduleIds.map { findScheduleEntityById(it) }, ) diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/SchedulePlaceAdapter.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/SchedulePlaceAdapter.kt new file mode 100644 index 00000000..d492116c --- /dev/null +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/SchedulePlaceAdapter.kt @@ -0,0 +1,94 @@ +package com.piikii.output.persistence.postgresql.adapter + +import com.piikii.application.domain.generic.LongTypeId +import com.piikii.application.domain.generic.UuidTypeId +import com.piikii.application.domain.place.SchedulePlace +import com.piikii.application.port.output.persistence.SchedulePlaceCommandPort +import com.piikii.application.port.output.persistence.SchedulePlaceQueryPort +import com.piikii.common.exception.ExceptionCode +import com.piikii.common.exception.PiikiiException +import com.piikii.output.persistence.postgresql.persistence.entity.SchedulePlaceEntity +import com.piikii.output.persistence.postgresql.persistence.repository.SchedulePlaceRepository +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Transactional + +@Repository +@Transactional(readOnly = true) +class SchedulePlaceAdapter( + private val schedulePlaceRepository: SchedulePlaceRepository, +) : SchedulePlaceQueryPort, SchedulePlaceCommandPort { + override fun findAllByRoomUid(roomUid: UuidTypeId): List { + return schedulePlaceRepository.findAllByRoomUid(roomUid).map { it.toDomain() } + } + + override fun findAllByPlaceId(placeId: LongTypeId): List { + return schedulePlaceRepository.findAllByPlaceId(placeId).map { it.toDomain() } + } + + override fun findAllConfirmedByRoomId(roomId: UuidTypeId): List { + return schedulePlaceRepository.findAllByRoomUidAndConfirmed(roomId, true).map { it.toDomain() } + } + + override fun findByRoomUidAndPlaceId( + roomUid: UuidTypeId, + placeId: LongTypeId, + ): SchedulePlace { + return schedulePlaceRepository.findByRoomUidAndPlaceId(roomUid, placeId) ?.toDomain() + ?: throw PiikiiException( + exceptionCode = ExceptionCode.NOT_FOUNDED, + detailMessage = "Not Found SchedulePlace: roomId : $roomUid, placeId: $placeId", + ) + } + + override fun findConfirmedByScheduleId(scheduleId: LongTypeId): SchedulePlace? { + return schedulePlaceRepository.findByScheduleIdAndConfirmed(scheduleId, true)?.toDomain() + } + + override fun findAllByRoomUidAndPaceIds( + roomUid: UuidTypeId, + placeIds: List, + ): List { + return schedulePlaceRepository.findByRoomUidAndPlaceIdIn(roomUid, placeIds.map { it.getValue() }) + .map { it.toDomain() } + } + + override fun findById(id: LongTypeId): SchedulePlace { + return find(id).toDomain() + } + + override fun findAllByIdIn(ids: List): List { + return schedulePlaceRepository.findAllByIdIn(ids.map { it.getValue() }).map { it.toDomain() } + } + + override fun saveAll(schedulePlaces: List) { + val schedulePlaceEntities = schedulePlaces.map { SchedulePlaceEntity(it) } + schedulePlaceRepository.saveAll(schedulePlaceEntities) + } + + override fun deleteAllByPlaceIdAndScheduleIds( + placeId: LongTypeId, + scheduleIds: List, + ) { + schedulePlaceRepository.deleteAllByPlaceIdAndScheduleIdIn(placeId, scheduleIds.map { it.getValue() }) + } + + override fun deleteAllByPlaceId(placeId: LongTypeId) { + schedulePlaceRepository.deleteAllByPlaceId(placeId) + } + + override fun update( + targetId: LongTypeId, + schedulePlace: SchedulePlace, + ) { + val schedulePlaceEntity = find(targetId) + schedulePlaceEntity.update(schedulePlace) + } + + private fun find(id: LongTypeId): SchedulePlaceEntity { + return schedulePlaceRepository.findByIdOrNull(id.getValue()) ?: throw PiikiiException( + exceptionCode = ExceptionCode.NOT_FOUNDED, + detailMessage = "schedulePlaceId : $id", + ) + } +} diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/VoteAdapter.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/VoteAdapter.kt index 200feb0d..a7db0f84 100644 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/VoteAdapter.kt +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/adapter/VoteAdapter.kt @@ -21,18 +21,18 @@ class VoteAdapter( voteRepository.saveAll(votes.map(VoteEntity::from)) } - override fun findAllByPlaceIds(placeIds: List): List { - return voteRepository.findAllByPlaceIdIn(placeIds.map { it.getValue() }).map { it.toDomain() } + override fun findAllBySchedulePlaceIds(schedulePlaceIds: List): List { + return voteRepository.findAllBySchedulePlaceIdIn(schedulePlaceIds.map { it.getValue() }).map { it.toDomain() } } override fun findAllByUserUid(userUid: UuidTypeId): List { return voteRepository.findAllByUserUid(userUid.getValue()).map { it.toDomain() } } - override fun findAgreeCountByPlaceId(votes: List): Map { + override fun findAgreeCountBySchedulePlaceId(votes: List): Map { return votes .filter { it.result == VoteResult.AGREE } - .groupingBy { it.placeId.getValue() } + .groupingBy { it.schedulePlaceId.getValue() } .eachCount() } } diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/SchedulePlaceEntity.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/SchedulePlaceEntity.kt index 33d671a0..1fc9e91c 100644 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/SchedulePlaceEntity.kt +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/entity/SchedulePlaceEntity.kt @@ -7,9 +7,11 @@ import com.piikii.output.persistence.postgresql.persistence.common.BaseEntity import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.Table +import org.hibernate.annotations.DynamicUpdate @Entity @Table(name = "schedule_place", schema = "piikii") +@DynamicUpdate class SchedulePlaceEntity( @Column(name = "room_uid", nullable = false, updatable = false) val roomUid: UuidTypeId, @@ -19,11 +21,11 @@ class SchedulePlaceEntity( var placeId: LongTypeId, @Column(name = "confirmed", nullable = false) var confirmed: Boolean = false, -): BaseEntity() { - constructor(schedulePlace: SchedulePlace): this( +) : BaseEntity() { + constructor(schedulePlace: SchedulePlace) : this( roomUid = schedulePlace.roomUid, scheduleId = schedulePlace.scheduleId, - placeId = schedulePlace.placeId + placeId = schedulePlace.placeId, ) fun toDomain(): SchedulePlace { @@ -35,4 +37,8 @@ class SchedulePlaceEntity( confirmed = confirmed, ) } + + fun update(schedulePlace: SchedulePlace) { + this.confirmed = schedulePlace.confirmed + } } diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/PlaceRepository.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/PlaceRepository.kt index 3e921c14..684e429a 100644 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/PlaceRepository.kt +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/PlaceRepository.kt @@ -7,10 +7,5 @@ import org.springframework.data.jpa.repository.JpaRepository interface PlaceRepository : JpaRepository { fun findAllByRoomUid(roomUid: UuidTypeId): List - fun findByScheduleIdAndConfirmed( - scheduleId: Long, - confirmed: Boolean, - ): List - - fun deleteByScheduleIdIn(scheduleIds: List) + fun deleteAllByIdIn(ids: List) } diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/SchedulePlaceRepository.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/SchedulePlaceRepository.kt new file mode 100644 index 00000000..47554ac9 --- /dev/null +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/SchedulePlaceRepository.kt @@ -0,0 +1,45 @@ +package com.piikii.output.persistence.postgresql.persistence.repository + +import com.piikii.application.domain.generic.LongTypeId +import com.piikii.application.domain.generic.UuidTypeId +import com.piikii.output.persistence.postgresql.persistence.entity.SchedulePlaceEntity +import org.springframework.data.jpa.repository.JpaRepository + +interface SchedulePlaceRepository : JpaRepository { + fun findAllByRoomUid(roomUid: UuidTypeId): List + + fun findAllByPlaceId(placeId: LongTypeId): List + + fun deleteAllByPlaceIdAndScheduleIdIn( + placeId: LongTypeId, + scheduleIds: List, + ) + + fun deleteAllByPlaceId(placeId: LongTypeId) + + fun findAllByScheduleIdIn(scheduleIds: List): List + + fun deleteAllByScheduleIdIn(scheduleIds: List) + + fun findAllByRoomUidAndConfirmed( + roomUid: UuidTypeId, + isConfirmed: Boolean, + ): List + + fun findByRoomUidAndPlaceId( + roomUid: UuidTypeId, + placeId: LongTypeId, + ): SchedulePlaceEntity? + + fun findByScheduleIdAndConfirmed( + scheduleId: LongTypeId, + isConfirmed: Boolean, + ): SchedulePlaceEntity? + + fun findByRoomUidAndPlaceIdIn( + roomUid: UuidTypeId, + scheduleIds: List, + ): List + + fun findAllByIdIn(ids: List): List +} diff --git a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/VoteRepository.kt b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/VoteRepository.kt index 11034e8f..0eff227e 100644 --- a/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/VoteRepository.kt +++ b/piikii-output-persistence/postgresql/src/main/kotlin/com/piikii/output/persistence/postgresql/persistence/repository/VoteRepository.kt @@ -5,7 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository import java.util.UUID interface VoteRepository : JpaRepository { - fun findAllByPlaceIdIn(placeIds: Collection): List + fun findAllBySchedulePlaceIdIn(schedulePlaceIds: Collection): List fun findAllByUserUid(userUid: UUID): List } diff --git a/piikii-output-persistence/postgresql/src/test/kotlin/com/piikii/output/persistence/postgresql/adapter/VoteAdapterTest.kt b/piikii-output-persistence/postgresql/src/test/kotlin/com/piikii/output/persistence/postgresql/adapter/VoteAdapterTest.kt index acb1596c..98a1a1bd 100644 --- a/piikii-output-persistence/postgresql/src/test/kotlin/com/piikii/output/persistence/postgresql/adapter/VoteAdapterTest.kt +++ b/piikii-output-persistence/postgresql/src/test/kotlin/com/piikii/output/persistence/postgresql/adapter/VoteAdapterTest.kt @@ -29,15 +29,15 @@ class VoteAdapterTest { val userUid = UuidTypeId(UUID.randomUUID()) val votes = listOf( - Vote(id = LongTypeId(1), userUid = userUid, placeId = placeId1, result = VoteResult.AGREE), - Vote(id = LongTypeId(2), userUid = userUid, placeId = placeId1, result = VoteResult.AGREE), - Vote(id = LongTypeId(3), userUid = userUid, placeId = placeId2, result = VoteResult.AGREE), - Vote(id = LongTypeId(4), userUid = userUid, placeId = placeId1, result = VoteResult.DISAGREE), - Vote(id = LongTypeId(5), userUid = userUid, placeId = placeId2, result = VoteResult.DISAGREE), + Vote(id = LongTypeId(1), userUid = userUid, schedulePlaceId = placeId1, result = VoteResult.AGREE), + Vote(id = LongTypeId(2), userUid = userUid, schedulePlaceId = placeId1, result = VoteResult.AGREE), + Vote(id = LongTypeId(3), userUid = userUid, schedulePlaceId = placeId2, result = VoteResult.AGREE), + Vote(id = LongTypeId(4), userUid = userUid, schedulePlaceId = placeId1, result = VoteResult.DISAGREE), + Vote(id = LongTypeId(5), userUid = userUid, schedulePlaceId = placeId2, result = VoteResult.DISAGREE), ) // when - val result = voteAdapter.findAgreeCountByPlaceId(votes) + val result = voteAdapter.findAgreeCountBySchedulePlaceId(votes) // then assertThat(result[placeId1.getValue()]).isEqualTo(2)