어떤 이벤트(공연)에 대해 사람들의 선호도를 확인하고, 인기 이벤트를 기록하기 위해 좋아요 기능을 구현하기로 했다.
기능 자체는 아주 간단한 것 같다. 좋아요를 누르면 True 다시 누르면 False 만 하면 되는거 아닌가?
아니다.
사용자 마다 좋아요 를 체크한 내용을 확인할 수 있어야 하고, 좋아요를 누른 이벤트에 대해선 누가/언제 눌렀는지. 좋아요 취소 누른 날짜는 어떤지? 좋아요 수는 어떻게 확인할지? 몇몇 고민이 필요했다.
모든 사용자들의 좋아요 를 관리할 테이블 'likes' 를 생성하고 유저가 좋아요를 누를 때마다 이를 기록한다.
Entity는 user / event 를 각각 N:1 관계로 설정하여 유저나 이벤트가 여러개의 좋아요를 갖는 것으로 구성한다.
( + BaseEntity 를 통해 CreatedDate 와 LastModifiedDate, isDeleted 를 상속받도록 함 )
Event 에선 likeRepository 에서 해당 eventId 의 갯수를 세서 LikeCount 를 보여줄 수 있도록 한다.
@Entity
@SQLDelete(sql = "UPDATE likes SET is_deleted = true WHERE id = ?") // DELETE 쿼리 날아올 시 대신 실행
@SQLRestriction("is_deleted = false")
@Table(name = "likes")
class Like (
@ManyToOne
@JoinColumn(name = "member_id")
val member: Member,
@ManyToOne
@JoinColumn(name = "event_id")
val event : Event,
) : BaseEntity() {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id:Long? = null
}
Like Entity 는 간단히 만들고 이제 Controller 로 와서도 작은 고민이 있었다.
Like 를 생성하는건 Post. 지우는건 Delete. 수정(복원) 은 Put이나 Patch.
그런데 처음 좋아요를 누를 때는 생성이 되고 두 번째 누를 때는 삭제( isDelete = true )
세 번째 누를 때는 복원( isDelete = false ) 로 복합적인 기능의 메서드가 될 텐데 어떤 Mapping 으로 묶어야 할까? 고민이 되었다.
어쨌든 최초는 생성이니 Post? isDelete 항목을 계속 수정하고 있으니 Put 이나 Patch..?
다른 프로젝트들을 확인해보니 이는 FE 와 상의를 통해 어떤 메서드로 호출할지 정하기도 하고, 대부분 POST Mappiong 으로 진행하는 것 같다.
override fun chkLike(memberId: Long, eventId: Long) {
val member = memberRepository.findByIdOrNull(memberId)
?:throw NotFoundException()
val event = eventRepository.findByIdOrNull(eventId)
?:throw NotFoundException()
likeRepository.findLikeByMemberIdAndEventId(memberId, eventId)
?.let{
it.isDeleted = !it.isDeleted
event.likeCount += if(it.isDeleted) 1 else -1
likeRepository.save(it)
}
?:run{
event.likeCount++
likeRepository.save(Like(member,event))
}
eventRepository.save(event)
}
override fun updateLike() {
// 이벤트 id 리스트를 Like 에서 가져와서
likeRepository.getEventIdList().map{e_id ->
// 각 id 마다 해당하는 like 가 몇개인지 확인하고 // 각 이벤트 객체의 count 를 저장
val event = eventRepository.findByIdOrNull(e_id)
?.also {e ->
e.likeCount = likeRepository.countEventId(e.id!!).toInt()
}
?: throw NotFoundException()
eventRepository.save(event)
}
}
간단해보이는 내용이더라도 요청 데이터가 많아지면 예상치 못한 문제가 발생할 수 있으니 항상 주의해야 함을 다시 느끼게 되었다. 비슷한 예로 LIKE 쿼리를 통한 검색 문제로 한참 고생했던 일들이 떠오르기도 했다. 항상 다양한 상황을 고려하고 대비하는 개발자가 되어야겠다..!