Skip to content

Commit

Permalink
Optimize member login
Browse files Browse the repository at this point in the history
  • Loading branch information
Ziedelth committed May 6, 2024
1 parent 1a4f4af commit 043b425
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package fr.shikkanime.controllers.api

import com.google.inject.Inject
import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.AllFollowedEpisodeDto
import fr.shikkanime.dtos.GenericDto
import fr.shikkanime.dtos.MemberDto
import fr.shikkanime.services.MemberFollowAnimeService
import fr.shikkanime.services.MemberFollowEpisodeService
import fr.shikkanime.services.MemberService
import fr.shikkanime.services.caches.MemberCacheService
import fr.shikkanime.utils.StringUtils
import fr.shikkanime.utils.routes.*
import fr.shikkanime.utils.routes.method.Delete
Expand All @@ -23,6 +22,9 @@ class MemberController {
@Inject
private lateinit var memberService: MemberService

@Inject
private lateinit var memberCacheService: MemberCacheService

@Inject
private lateinit var memberFollowAnimeService: MemberFollowAnimeService

Expand All @@ -42,7 +44,7 @@ class MemberController {

do {
identifier = StringUtils.generateRandomString(12)
} while (memberService.findPrivateMember(identifier) != null)
} while (memberCacheService.findPrivateMember(identifier) != null)

memberService.savePrivateMember(identifier)
return Response.created(mapOf("identifier" to identifier))
Expand All @@ -57,8 +59,7 @@ class MemberController {
]
)
private fun loginPrivateMember(@BodyParam identifier: String): Response {
val privateMember = memberService.findPrivateMember(identifier) ?: return Response.notFound()
return Response.ok(AbstractConverter.convert(privateMember, MemberDto::class.java))
return Response.ok(memberCacheService.findPrivateMember(identifier) ?: return Response.notFound())
}

@Path("/animes")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,16 @@ class MemberToMemberDtoConverter : AbstractConverter<Member, MemberDto>() {

override fun convert(from: Member): MemberDto {
val tokenDto = convert(from, TokenDto::class.java)
val followedEpisodes = memberFollowEpisodeService.getAllFollowedEpisodes(from)

return MemberDto(
uuid = from.uuid!!,
token = tokenDto.token!!,
creationDateTime = from.creationDateTime.withUTCString(),
lastUpdateDateTime = from.lastUpdateDateTime.withUTCString(),
isPrivate = from.isPrivate,
followedAnimes = memberFollowAnimeService.getAllFollowedAnimes(from).mapNotNull { it.uuid },
followedEpisodes = followedEpisodes.mapNotNull { it.uuid },
totalDuration = followedEpisodes.sumOf { it.duration }
followedAnimes = memberFollowAnimeService.getAllFollowedAnimesUUID(from),
followedEpisodes = memberFollowEpisodeService.getAllFollowedEpisodesUUID(from),
totalDuration = memberFollowEpisodeService.getTotalDuration(from),
)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package fr.shikkanime.repositories

import fr.shikkanime.entities.*
import com.google.inject.Inject
import fr.shikkanime.entities.*
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.entities.enums.EpisodeType
import fr.shikkanime.services.MemberFollowAnimeService
Expand Down Expand Up @@ -32,8 +32,8 @@ class EpisodeVariantRepository : AbstractRepository<EpisodeVariant>() {
val predicates = mutableListOf(countryPredicate, datePredicate)

member?.let {
val animePredicate = root[EpisodeVariant_.mapping][EpisodeMapping_.anime].`in`(
memberFollowAnimeService.getAllFollowedAnimes(it)
val animePredicate = root[EpisodeVariant_.mapping][EpisodeMapping_.anime].get<UUID>(Anime_.UUID).`in`(
memberFollowAnimeService.getAllFollowedAnimesUUID(it)
)
predicates.add(animePredicate)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package fr.shikkanime.repositories

import fr.shikkanime.entities.Anime
import fr.shikkanime.entities.Member
import fr.shikkanime.entities.MemberFollowAnime
import fr.shikkanime.entities.MemberFollowAnime_
import fr.shikkanime.entities.*
import java.util.*

class MemberFollowAnimeRepository : AbstractRepository<MemberFollowAnime>() {
override fun getEntityClass() = MemberFollowAnime::class.java
Expand All @@ -25,12 +23,12 @@ class MemberFollowAnimeRepository : AbstractRepository<MemberFollowAnime>() {
}
}

fun getAllFollowedAnimes(member: Member): List<Anime> {
fun getAllFollowedAnimesUUID(member: Member): List<UUID> {
return inTransaction {
val cb = it.criteriaBuilder
val query = cb.createQuery(Anime::class.java)
val query = cb.createQuery(UUID::class.java)
val root = query.from(getEntityClass())
query.select(root[MemberFollowAnime_.anime])
query.select(root[MemberFollowAnime_.anime][Anime_.UUID])

query.where(
cb.equal(root[MemberFollowAnime_.member], member)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package fr.shikkanime.repositories

import fr.shikkanime.entities.EpisodeMapping
import fr.shikkanime.entities.Member
import fr.shikkanime.entities.MemberFollowEpisode
import fr.shikkanime.entities.MemberFollowEpisode_
import fr.shikkanime.entities.*
import java.util.*

class MemberFollowEpisodeRepository : AbstractRepository<MemberFollowEpisode>() {
override fun getEntityClass() = MemberFollowEpisode::class.java
Expand All @@ -25,12 +23,12 @@ class MemberFollowEpisodeRepository : AbstractRepository<MemberFollowEpisode>()
}
}

fun getAllFollowedEpisodes(member: Member): List<EpisodeMapping> {
fun getAllFollowedEpisodesUUID(member: Member): List<UUID> {
return inTransaction {
val cb = it.criteriaBuilder
val query = cb.createQuery(EpisodeMapping::class.java)
val query = cb.createQuery(UUID::class.java)
val root = query.from(getEntityClass())
query.select(root[MemberFollowEpisode_.episode])
query.select(root[MemberFollowEpisode_.episode][EpisodeMapping_.UUID])

query.where(
cb.equal(root[MemberFollowEpisode_.member], member)
Expand All @@ -40,4 +38,21 @@ class MemberFollowEpisodeRepository : AbstractRepository<MemberFollowEpisode>()
.resultList
}
}

fun getTotalDuration(member: Member): Long {
return inTransaction {
val cb = it.criteriaBuilder
val query = cb.createQuery(Long::class.java)
val root = query.from(getEntityClass())
query.select(cb.sum(root[MemberFollowEpisode_.episode][EpisodeMapping_.duration]))

query.where(
cb.equal(root[MemberFollowEpisode_.member], member)
)

createReadOnlyQuery(it, query)
.resultList
.firstOrNull() ?: 0L
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class MemberFollowAnimeService : AbstractService<MemberFollowAnime, MemberFollow

override fun getRepository() = memberFollowAnimeRepository

fun getAllFollowedAnimes(member: Member) = memberFollowAnimeRepository.getAllFollowedAnimes(member)
fun getAllFollowedAnimesUUID(member: Member) = memberFollowAnimeRepository.getAllFollowedAnimesUUID(member)

fun follow(uuidUser: UUID, anime: GenericDto): Response {
val member = memberService.find(uuidUser) ?: return Response.notFound()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class MemberFollowEpisodeService : AbstractService<MemberFollowEpisode, MemberFo

override fun getRepository() = memberFollowEpisodeRepository

fun getAllFollowedEpisodes(member: Member) = memberFollowEpisodeRepository.getAllFollowedEpisodes(member)
fun getAllFollowedEpisodesUUID(member: Member) = memberFollowEpisodeRepository.getAllFollowedEpisodesUUID(member)

fun getTotalDuration(member: Member) = memberFollowEpisodeRepository.getTotalDuration(member)

fun followAll(uuidUser: UUID, anime: GenericDto): Response {
val member = memberService.find(uuidUser) ?: return Response.notFound()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package fr.shikkanime.services.caches

import com.google.inject.Inject
import fr.shikkanime.converters.AbstractConverter
import fr.shikkanime.dtos.MemberDto
import fr.shikkanime.entities.Member
import fr.shikkanime.entities.MemberFollowAnime
import fr.shikkanime.entities.MemberFollowEpisode
import fr.shikkanime.services.MemberService
import fr.shikkanime.utils.MapCache
import java.util.*
Expand All @@ -14,5 +18,13 @@ class MemberCacheService : AbstractCacheService {
memberService.find(it)
}

private val findPrivateMemberCache =
MapCache<String, MemberDto?>(classes = listOf(Member::class.java, MemberFollowAnime::class.java, MemberFollowEpisode::class.java)) {
memberService.findPrivateMember(it)
?.let { member -> AbstractConverter.convert(member, MemberDto::class.java) }
}

fun find(uuid: UUID) = cache[uuid]

fun findPrivateMember(identifier: String) = findPrivateMemberCache[identifier]
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ class AnimeControllerTest {
}.apply {
assertEquals(HttpStatusCode.OK, status)
val findPrivateMember = memberService.findPrivateMember(identifier)
val followedAnimes = memberFollowAnimeService.getAllFollowedAnimes(findPrivateMember!!)
val followedAnimesUUID = memberFollowAnimeService.getAllFollowedAnimesUUID(findPrivateMember!!)
assertNotNull(findPrivateMember)
assertEquals(1, followedAnimes.size)
assertEquals(anime1.uuid, followedAnimes.first().uuid)
assertEquals(1, followedAnimesUUID.size)
assertEquals(anime1.uuid, followedAnimesUUID.first())
}

client.get("/api/v1/animes/weekly") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import fr.shikkanime.dtos.GenericDto
import fr.shikkanime.dtos.MemberDto
import fr.shikkanime.entities.Anime
import fr.shikkanime.entities.EpisodeMapping
import fr.shikkanime.entities.Member
import fr.shikkanime.entities.enums.CountryCode
import fr.shikkanime.entities.enums.EpisodeType
import fr.shikkanime.module
import fr.shikkanime.services.*
import fr.shikkanime.utils.Constant
import fr.shikkanime.utils.MapCache
import fr.shikkanime.utils.ObjectParser
import io.ktor.client.request.*
import io.ktor.client.statement.*
Expand Down Expand Up @@ -49,6 +51,7 @@ class MemberControllerTest {
memberService.deleteAll()
episodeMappingService.deleteAll()
animeService.deleteAll()
MapCache.invalidate(Member::class.java)
}

@Test
Expand Down Expand Up @@ -143,10 +146,10 @@ class MemberControllerTest {
}.apply {
assertEquals(HttpStatusCode.OK, status)
val findPrivateMember = memberService.findPrivateMember(identifier)
val followedAnimes = memberFollowAnimeService.getAllFollowedAnimes(findPrivateMember!!)
val followedAnimesUUID = memberFollowAnimeService.getAllFollowedAnimesUUID(findPrivateMember!!)
assertNotNull(findPrivateMember)
assertEquals(1, followedAnimes.size)
assertEquals(anime.uuid, followedAnimes.first().uuid)
assertEquals(1, followedAnimesUUID.size)
assertEquals(anime.uuid, followedAnimesUUID.first())
}
}
}
Expand Down Expand Up @@ -197,10 +200,10 @@ class MemberControllerTest {
}.apply {
assertEquals(HttpStatusCode.OK, status)
val findPrivateMember = memberService.findPrivateMember(identifier)
val followedAnimes = memberFollowAnimeService.getAllFollowedAnimes(findPrivateMember!!)
val followedAnimesUUID = memberFollowAnimeService.getAllFollowedAnimesUUID(findPrivateMember!!)
assertNotNull(findPrivateMember)
assertEquals(1, followedAnimes.size)
assertEquals(anime.uuid, followedAnimes.first().uuid)
assertEquals(1, followedAnimesUUID.size)
assertEquals(anime.uuid, followedAnimesUUID.first())
}

client.delete("/api/v1/members/animes") {
Expand All @@ -210,9 +213,9 @@ class MemberControllerTest {
}.apply {
assertEquals(HttpStatusCode.OK, status)
val findPrivateMember = memberService.findPrivateMember(identifier)
val followedAnimes = memberFollowAnimeService.getAllFollowedAnimes(findPrivateMember!!)
val followedAnimesUUID = memberFollowAnimeService.getAllFollowedAnimesUUID(findPrivateMember!!)
assertNotNull(findPrivateMember)
assertEquals(0, followedAnimes.size)
assertEquals(0, followedAnimesUUID.size)
}
}
}
Expand Down Expand Up @@ -254,10 +257,10 @@ class MemberControllerTest {
}.apply {
assertEquals(HttpStatusCode.OK, status)
val findPrivateMember = memberService.findPrivateMember(identifier)
val followedEpisodes = memberFollowEpisodeService.getAllFollowedEpisodes(findPrivateMember!!)
val followedEpisodesUUID = memberFollowEpisodeService.getAllFollowedEpisodesUUID(findPrivateMember!!)
assertNotNull(findPrivateMember)
assertEquals(1, followedEpisodes.size)
assertEquals(episode.uuid, followedEpisodes.first().uuid)
assertEquals(1, followedEpisodesUUID.size)
assertEquals(episode.uuid, followedEpisodesUUID.first())
}
}
}
Expand Down Expand Up @@ -318,10 +321,10 @@ class MemberControllerTest {
}.apply {
assertEquals(HttpStatusCode.OK, status)
val findPrivateMember = memberService.findPrivateMember(identifier)
val followedEpisodes = memberFollowEpisodeService.getAllFollowedEpisodes(findPrivateMember!!)
val followedEpisodesUUID = memberFollowEpisodeService.getAllFollowedEpisodesUUID(findPrivateMember!!)
assertNotNull(findPrivateMember)
assertEquals(1, followedEpisodes.size)
assertEquals(episode.uuid, followedEpisodes.first().uuid)
assertEquals(1, followedEpisodesUUID.size)
assertEquals(episode.uuid, followedEpisodesUUID.first())
}

client.delete("/api/v1/members/episodes") {
Expand All @@ -331,7 +334,7 @@ class MemberControllerTest {
}.apply {
assertEquals(HttpStatusCode.OK, status)
val findPrivateMember = memberService.findPrivateMember(identifier)
val followedEpisodes = memberFollowEpisodeService.getAllFollowedEpisodes(findPrivateMember!!)
val followedEpisodes = memberFollowEpisodeService.getAllFollowedEpisodesUUID(findPrivateMember!!)
assertNotNull(findPrivateMember)
assertEquals(0, followedEpisodes.size)
}
Expand Down Expand Up @@ -377,7 +380,7 @@ class MemberControllerTest {
}.apply {
assertEquals(HttpStatusCode.OK, status)
val findPrivateMember = memberService.findPrivateMember(identifier)
val followedEpisodes = memberFollowEpisodeService.getAllFollowedEpisodes(findPrivateMember!!)
val followedEpisodes = memberFollowEpisodeService.getAllFollowedEpisodesUUID(findPrivateMember!!)
assertNotNull(findPrivateMember)
assertEquals(12, followedEpisodes.size)
}
Expand Down

0 comments on commit 043b425

Please sign in to comment.