diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt index 9f03a50..08a2904 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt @@ -1,41 +1,36 @@ package kr.co.vividnext.sodalive.live.room -import com.querydsl.core.types.OrderSpecifier -import com.querydsl.core.types.Predicate import com.querydsl.core.types.Projections import com.querydsl.core.types.dsl.CaseBuilder -import com.querydsl.core.types.dsl.Expressions import com.querydsl.jpa.impl.JPAQueryFactory import kr.co.vividnext.sodalive.can.use.CanUsage import kr.co.vividnext.sodalive.can.use.QUseCan.useCan import kr.co.vividnext.sodalive.can.use.QUseCanCalculate.useCanCalculate import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom +import kr.co.vividnext.sodalive.live.room.QQuarterLiveRankings.quarterLiveRankings import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationItem import kr.co.vividnext.sodalive.live.room.donation.QGetLiveRoomDonationItem -import kr.co.vividnext.sodalive.member.Member -import kr.co.vividnext.sodalive.member.QMember import kr.co.vividnext.sodalive.member.QMember.member -import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository -import java.time.LocalDate import java.time.LocalDateTime import java.time.ZoneId -import java.time.format.DateTimeFormatter @Repository interface LiveRoomRepository : JpaRepository, LiveRoomQueryRepository interface LiveRoomQueryRepository { - fun getLiveRoomList( - dateString: String?, - status: LiveRoomStatus, - pageable: Pageable, - member: Member, - timezone: String, + fun getLiveRoomListNow(offset: Long, limit: Long, timezone: String, isAdult: Boolean): List + + fun getLiveRoomListReservationWithDate( + date: LocalDateTime, + offset: Long, + limit: Long, isAdult: Boolean ): List + fun getLiveRoomListReservationWithoutDate(timezone: String, memberId: Long, isAdult: Boolean): List + fun getLiveRoom(id: Long): LiveRoom? fun getLiveRoomAndAccountId(roomId: Long, memberId: Long): LiveRoom? fun getRecentRoomInfo(memberId: Long, cloudFrontHost: String): GetRecentRoomInfoResponse? @@ -45,67 +40,94 @@ interface LiveRoomQueryRepository { } class LiveRoomQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : LiveRoomQueryRepository { - override fun getLiveRoomList( - dateString: String?, - status: LiveRoomStatus, - pageable: Pageable, - member: Member, - timezone: String, - isAdult: Boolean - ): List { - var where: Predicate - - if (status == LiveRoomStatus.NOW) { - where = liveRoom.channelName.isNotNull - .and(liveRoom.channelName.isNotEmpty) - } else { - where = if (dateString != null) { - val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") - val date = LocalDate.parse(dateString, dateTimeFormatter).atStartOfDay() - .atZone(ZoneId.of(timezone)) - .withZoneSameInstant(ZoneId.of("UTC")) - .toLocalDateTime() - - liveRoom.beginDateTime.goe(date) - .and(liveRoom.beginDateTime.lt(date.plusDays(1))) - .and( - liveRoom.channelName.isNull - .or(liveRoom.channelName.isEmpty) - ) - } else { - liveRoom.beginDateTime.gt( - LocalDateTime.now() - .atZone(ZoneId.of(timezone)) - .withZoneSameInstant(ZoneId.of("UTC")) - .toLocalDateTime() - ) - .and( - liveRoom.channelName.isNull - .or(liveRoom.channelName.isEmpty) - ) - } - } + override fun getLiveRoomListNow(offset: Long, limit: Long, timezone: String, isAdult: Boolean): List { + var where = liveRoom.channelName.isNotNull + .and(liveRoom.channelName.isNotEmpty) + .and(liveRoom.isActive.isTrue) + .and(liveRoom.member.isNotNull) if (!isAdult) { where = where.and(liveRoom.isAdult.isFalse) } - where = where.and(liveRoom.isActive.isTrue) + return queryFactory + .selectFrom(liveRoom) + .innerJoin(liveRoom.member, member) + .leftJoin(quarterLiveRankings).on(liveRoom.id.eq(quarterLiveRankings.roomId)) + .where(where) + .offset(offset) + .limit(limit) + .orderBy( + quarterLiveRankings.totalCan.desc(), + quarterLiveRankings.totalParticipants.desc(), + liveRoom.beginDateTime.desc(), + liveRoom.member.createdAt.desc() + ) + .fetch() + } + + override fun getLiveRoomListReservationWithDate( + date: LocalDateTime, + offset: Long, + limit: Long, + isAdult: Boolean + ): List { + var where = liveRoom.beginDateTime.goe(date) + .and(liveRoom.beginDateTime.lt(date.plusDays(1))) + .and( + liveRoom.channelName.isNull + .or(liveRoom.channelName.isEmpty) + ) + .and(liveRoom.isActive.isTrue) .and(liveRoom.member.isNotNull) + if (!isAdult) { + where = where.and(liveRoom.isAdult.isFalse) + } + return queryFactory .selectFrom(liveRoom) - .innerJoin(liveRoom.member, QMember.member) - .offset(pageable.offset) - .limit(pageable.pageSize.toLong()) + .innerJoin(liveRoom.member, member) + .where(where) + .offset(offset) + .limit(limit) + .orderBy(liveRoom.beginDateTime.asc()) + .fetch() + } + + override fun getLiveRoomListReservationWithoutDate( + timezone: String, + memberId: Long, + isAdult: Boolean + ): List { + var where = liveRoom.beginDateTime.gt( + LocalDateTime.now() + .atZone(ZoneId.of(timezone)) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + ) + .and( + liveRoom.channelName.isNull + .or(liveRoom.channelName.isEmpty) + ) + .and(liveRoom.isActive.isTrue) + .and(liveRoom.member.isNotNull) + + if (!isAdult) { + where = where.and(liveRoom.isAdult.isFalse) + } + + return queryFactory + .selectFrom(liveRoom) + .innerJoin(liveRoom.member, member) + .limit(10) .where(where) .orderBy( - *orderByFieldAccountId( - memberId = member.id!!, - status = status, - offset = pageable.offset, - dateString = dateString - ) + CaseBuilder() + .`when`(member.id.eq(memberId)).then(1) + .otherwise(2) + .asc(), + liveRoom.beginDateTime.asc() ) .fetch() } @@ -201,25 +223,4 @@ class LiveRoomQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : L ) .fetch() } - - private fun orderByFieldAccountId( - memberId: Long, - status: LiveRoomStatus, - offset: Long, - dateString: String? - ): Array> { - return if (status == LiveRoomStatus.NOW) { - arrayOf(Expressions.numberTemplate(Double::class.java, "function('rand')").asc()) - } else if (status == LiveRoomStatus.RESERVATION && offset == 0L && dateString == null) { - arrayOf( - CaseBuilder() - .`when`(member.id.eq(memberId)).then(1) - .otherwise(2) - .asc(), - liveRoom.beginDateTime.asc() - ) - } else { - arrayOf(liveRoom.beginDateTime.asc()) - } - } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt index 6cfc274..a4ac5e4 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt @@ -58,6 +58,7 @@ import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import org.springframework.web.multipart.MultipartFile +import java.time.LocalDate import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter @@ -115,16 +116,24 @@ class LiveRoomService( member: Member, timezone: String ): List { - return repository - .getLiveRoomList( - dateString = dateString, - status = status, - pageable = pageable, - member = member, - timezone = timezone, + val roomList = if (status == LiveRoomStatus.NOW) { + getLiveRoomListNow(pageable, timezone, isAdult = member.auth != null) + } else if (dateString != null) { + getLiveRoomListReservationWithDate( + dateString, + pageable, + timezone, isAdult = member.auth != null ) - .asSequence() + } else { + getLiveRoomListReservationWithoutDate( + timezone, + memberId = member.id!!, + isAdult = member.auth != null + ) + } + + return roomList .filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.member!!.id!!) } .map { val roomInfo = roomInfoRepository.findByIdOrNull(it.id!!) @@ -174,7 +183,43 @@ class LiveRoomService( isPrivateRoom = it.type == LiveRoomType.PRIVATE ) } - .toList() + } + + private fun getLiveRoomListNow(pageable: Pageable, timezone: String, isAdult: Boolean): List { + return repository.getLiveRoomListNow( + offset = pageable.offset, + limit = pageable.pageSize.toLong(), + timezone = timezone, + isAdult = isAdult + ) + } + + private fun getLiveRoomListReservationWithDate( + dateString: String, + pageable: Pageable, + timezone: String, + isAdult: Boolean + ): List { + val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + val date = LocalDate.parse(dateString, dateTimeFormatter).atStartOfDay() + .atZone(ZoneId.of(timezone)) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + + return repository.getLiveRoomListReservationWithDate( + date = date, + offset = pageable.offset, + limit = pageable.pageSize.toLong(), + isAdult = isAdult + ) + } + + private fun getLiveRoomListReservationWithoutDate( + timezone: String, + memberId: Long, + isAdult: Boolean + ): List { + return repository.getLiveRoomListReservationWithoutDate(timezone, memberId, isAdult) } @Transactional diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/QuarterLiveRankings.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/QuarterLiveRankings.kt new file mode 100644 index 0000000..d484073 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/QuarterLiveRankings.kt @@ -0,0 +1,16 @@ +package kr.co.vividnext.sodalive.live.room + +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id + +@Entity +data class QuarterLiveRankings( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + var id: Long? = null, + val roomId: Long, + val totalCan: Int, + val totalParticipants: Int +)