Skip to content

Commit

Permalink
Improve pagination and include seasonal endpoint for directory
Browse files Browse the repository at this point in the history
  • Loading branch information
jeluchu committed Jan 13, 2025
1 parent df6baa7 commit 78f0af1
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 31 deletions.
13 changes: 2 additions & 11 deletions src/main/kotlin/com/jeluchu/core/utils/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,10 @@ object BaseUrls {
}

object Endpoints {
const val FULL = "full"
const val ANIME = "anime/"
const val SCHEDULES = "schedules"
const val TOP_ANIME = "top/anime"
const val TOP_MANGA = "top/manga"
const val TOP_PEOPLE = "top/people"
const val STATISTICS = "statistics"
const val CHARACTERS = "characters"
const val TOP_CHARACTER = "top/characters"
const val LAST_EPISODES = "list/latest-episodes"
}
Expand All @@ -22,22 +18,19 @@ object Routes {
const val TOP = "/top"
const val ANIME = "/anime"
const val MANGA = "/manga"
const val PAGE = "/{page}"
const val PEOPLE = "/people"
const val SCHEDULE = "/schedule"
const val DIRECTORY = "/directory"
const val CHARACTER = "/characters"
const val LAST_EPISODES = "/lastEpisodes"
const val ID = "/{id}"
const val ANIME_TYPE = "/{type}"
const val TYPE = "/{type}"
const val SEASON = "/{year}/{season}"
const val DAY = "/{day}"
const val TOP_CHARACTER = "/top/character"
const val RANKINGS = "/{type}/{filter}/{page}"
}

object TimerKey {
const val KEY = "key"
const val RANKING = "ranking"
const val SCHEDULE = "schedule"
const val LAST_UPDATED = "lastUpdated"
const val ANIME_TYPE = "anime_"
Expand All @@ -47,12 +40,10 @@ object TimerKey {
object Collections {
const val TIMERS = "timers"
const val SCHEDULES = "schedule"
const val ANIME_TYPE = "anime_"
const val ANIME_DETAILS = "anime_details"
const val LAST_EPISODES = "last_episodes"
const val ANIME_RANKING = "anime_ranking"
const val MANGA_RANKING = "manga_ranking"
const val PEOPLE_RANKING = "people_ranking"
const val ANIME_DIRECTORY = "anime_directory"
const val CHARACTER_RANKING = "character_ranking"
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ fun documentToCharacterTopEntity(doc: Document) = CharacterTopEntity(
fun documentToAnimeTypeEntity(doc: Document) = AnimeTypeEntity(
score = doc.getString("score"),
malId = doc.getIntSafe("malId"),
year = doc.getIntSafe("year"),
season = doc.getStringSafe("season"),
type = doc.getStringSafe("type"),
title = doc.getStringSafe("title"),
image = doc.getStringSafe("poster"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ data class AnimeTypeEntity(
val malId: Int? = 0,
val type: String? = "",
val episodes: Int? = 0,
val year: Int? = 0,
val season: String? = "",
val title: String? = "",
val image: String? = "",
val score: String? = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ fun Route.animeEndpoints(

route(Routes.DIRECTORY) {
getToJson { service.getDirectory(call) }
getToJson(Routes.ANIME_TYPE) { directoryService.getAnimeByType(call) }
getToJson(Routes.TYPE) { directoryService.getAnimeByType(call) }
getToJson(Routes.SEASON) { directoryService.getAnimeBySeason(call) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class AnimeService(
.limit(size)
.toList()

val elements = animes.map { documentToAnimeDirectoryEntity(it) }
val elements = animes.map { documentToAnimeTypeEntity(it) }

val response = PaginationResponse(
page = page,
Expand Down Expand Up @@ -123,10 +123,4 @@ class AnimeService(
val directory = map { documentToLastEpisodesEntity(it) }
return Json.encodeToString(directory)
}

private fun List<Document>.documentAnimeTypeMapper(): String {
val directory = map { documentToAnimeTypeEntity(it) }
return Json.encodeToString(directory)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,16 @@ class DirectoryService(
ErrorResponse(ErrorMessages.InvalidAnimeType.message)
)

val timerKey = "${TimerKey.ANIME_TYPE}${param.lowercase()}"
val timerKey = "${TimerKey.ANIME_TYPE}${param.lowercase()}_$page"
val collection = database.getCollection(timerKey)

val needsUpdate = timers.needsUpdate(
amount = 30,
key = timerKey,
unit = TimeUnit.DAY,
)

if (needsUpdate) {
val collection = database.getCollection(timerKey)
collection.deleteMany(Document())

val animes = directory
Expand All @@ -62,31 +63,88 @@ class DirectoryService(

val response = PaginationResponse(
page = page,
size = size,
data = animeTypes,
totalItems = directory.countDocuments().toInt()
size = animeTypes.size
)

call.respond(HttpStatusCode.OK, Json.encodeToString(response))
} else {
val elements = directory.find()
val elements = collection
.find()
.skip(skipCount)
.limit(size)
.toList()

val responseItems = elements.map { documentToAnimeTypeEntity(it) }
val response = PaginationResponse(
page = page,
size = size,
totalItems = directory.countDocuments().toInt(),
data = elements.map { documentToAnimeTypeEntity(it) }
data = responseItems,
size = responseItems.size
)

call.respond(HttpStatusCode.OK, Json.encodeToString(response))
}
}

private fun List<Document>.documentAnimeTypeMapper(): String {
val directory = map { documentToAnimeTypeEntity(it) }
return Json.encodeToString(directory)
suspend fun getAnimeBySeason(call: RoutingCall) {
val page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1
val size = call.request.queryParameters["size"]?.toIntOrNull() ?: 10
val year = call.parameters["year"]?.toIntOrNull() ?: throw IllegalArgumentException(ErrorMessages.NotFound.message)
val season = call.parameters["season"] ?: throw IllegalArgumentException(ErrorMessages.NotFound.message)

if (page < 1 || size < 1) call.respond(HttpStatusCode.BadRequest, ErrorMessages.InvalidSizeAndPage.message)
val skipCount = (page - 1) * size

val timerKey = "${TimerKey.ANIME_TYPE}${year}_${season}_$page"
val collection = database.getCollection(timerKey)

val needsUpdate = timers.needsUpdate(
amount = 30,
key = timerKey,
unit = TimeUnit.DAY,
)

if (needsUpdate) {
collection.deleteMany(Document())

val animes = directory
.find(
Filters.and(
Filters.eq("year", year),
Filters.eq("season", season)
)
)
.skip(skipCount)
.limit(size)
.toList()

val animeTypes = animes.map { documentToAnimeTypeEntity(it) }
val documents = animeTypes.map { anime -> Document.parse(Json.encodeToString(anime)) }
if (documents.isNotEmpty()) collection.insertMany(documents)
timers.update(timerKey)

val response = PaginationResponse(
page = page,
data = animeTypes,
size = animeTypes.size
)

call.respond(HttpStatusCode.OK, Json.encodeToString(response))
} else {
val elements = collection
.find()
.skip(skipCount)
.limit(size)
.toList()

val responseItems = elements.map { documentToAnimeTypeEntity(it) }
val response = PaginationResponse(
page = page,
data = responseItems,
size = responseItems.size
)

call.respond(HttpStatusCode.OK, Json.encodeToString(response))
}
}
}

0 comments on commit 78f0af1

Please sign in to comment.