From 131a5c2efe81cdb8cb48163a1ecbf4aafb2b92cd Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 5 Aug 2024 08:53:07 +0100 Subject: [PATCH] api: optimize pagination!! --- .../fascinated/common/PaginationBuilder.java | 53 ++++++++++++++++--- .../scoresaber/ScoreSaberScoreResponse.java | 14 +++++ .../repository/ScoreRepository.java | 3 +- .../cc/fascinated/services/ScoreService.java | 29 ++-------- 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/API/src/main/java/cc/fascinated/common/PaginationBuilder.java b/API/src/main/java/cc/fascinated/common/PaginationBuilder.java index 9d5625b..3358df0 100644 --- a/API/src/main/java/cc/fascinated/common/PaginationBuilder.java +++ b/API/src/main/java/cc/fascinated/common/PaginationBuilder.java @@ -5,6 +5,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import java.util.List; +import java.util.function.Function; import java.util.function.Supplier; /** @@ -17,10 +18,15 @@ public class PaginationBuilder { */ private int itemsPerPage; + /** + * The total number of items. + */ + private int totalItems; + /** * The items to paginate. */ - private List items; + private Function> items; /** * Sets the number of items per page. @@ -33,14 +39,25 @@ public class PaginationBuilder { return this; } + /** + * Sets the total number of items. + * + * @param totalItems The total number of items. + * @return The pagination builder. + */ + public PaginationBuilder totalItems(Supplier totalItems) { + this.totalItems = totalItems.get(); + return this; + } + /** * Sets the items to paginate. * * @param getItems The items to paginate. * @return The pagination builder. */ - public PaginationBuilder fillItems(Supplier> getItems) { - this.items = getItems.get(); + public PaginationBuilder items(Function> getItems) { + this.items = getItems; return this; } @@ -56,23 +73,43 @@ public class PaginationBuilder { /** * Gets a page of items. * - * @param page The page number. + * @param page The page number. * @return The page. */ public Page getPage(int page) { - int totalItems = this.items.size(); - int totalPages = (int) Math.ceil((double) totalItems / this.itemsPerPage); + List items = this.items.apply(new FetchItems(page, this.itemsPerPage)); + int totalPages = (int) Math.ceil((double) this.totalItems / this.itemsPerPage); if (page < 1 || page > totalPages) { throw new BadRequestException("Invalid page number"); } - List items = this.items.subList((page - 1) * this.itemsPerPage, Math.min(page * this.itemsPerPage, totalItems)); return new Page<>( items, - new Page.Metadata(page, totalPages, totalItems) + new Page.Metadata(page, totalPages, this.totalItems) ); } + @AllArgsConstructor + @Getter + public static class FetchItems { + /** + * The current page. + */ + private final int currentPage; + + /** + * The items per page. + */ + private final int itemsPerPage; + + /** + * The amount of items to skip. + */ + public int skipAmount() { + return (currentPage - 1) * itemsPerPage; + } + } + @AllArgsConstructor @Getter public static class Page { diff --git a/API/src/main/java/cc/fascinated/model/score/impl/scoresaber/ScoreSaberScoreResponse.java b/API/src/main/java/cc/fascinated/model/score/impl/scoresaber/ScoreSaberScoreResponse.java index f6c93e4..317e7dc 100644 --- a/API/src/main/java/cc/fascinated/model/score/impl/scoresaber/ScoreSaberScoreResponse.java +++ b/API/src/main/java/cc/fascinated/model/score/impl/scoresaber/ScoreSaberScoreResponse.java @@ -31,4 +31,18 @@ public class ScoreSaberScoreResponse extends ScoreSaberScore { this.user = user; this.leaderboard = leaderboard; } + + /** + * Creates a new score saber score response. + * + * @param score the score to create the response from + * @param user the user that set the score + * @param leaderboard the leaderboard the score was set on + * @return the score saber score response + */ + public static ScoreSaberScoreResponse fromScore(ScoreSaberScore score, UserDTO user, Leaderboard leaderboard) { + return new ScoreSaberScoreResponse(score.getId(), score.getPlayerId(), score.getPlatform(), score.getPlatformScoreId(), score.getLeaderboardId(), + score.getRank(), score.getAccuracy(), score.getPp(), score.getScore(), score.getModifiers(), score.getMisses(), score.getBadCuts(), + score.getDeviceInformation(), score.getTimestamp(), score.getWeight(), score.getMultiplier(), score.getMaxCombo(), user, leaderboard); + } } diff --git a/API/src/main/java/cc/fascinated/repository/ScoreRepository.java b/API/src/main/java/cc/fascinated/repository/ScoreRepository.java index 2f3bad8..d771613 100644 --- a/API/src/main/java/cc/fascinated/repository/ScoreRepository.java +++ b/API/src/main/java/cc/fascinated/repository/ScoreRepository.java @@ -24,9 +24,10 @@ public interface ScoreRepository extends MongoRepository { @Aggregation(pipeline = { "{ $match: { platform: ?0, pp: { $gt: 0 } } }", "{ $sort: { pp: -1 } }", + "{ $skip: ?2 }", "{ $limit: ?1 }", }) - List getTopRankedScores(@NonNull Platform.Platforms platform, int amount); + List getTopRankedScores(@NonNull Platform.Platforms platform, int amount, int skip); /** * Gets all the ranked scores from the platform. diff --git a/API/src/main/java/cc/fascinated/services/ScoreService.java b/API/src/main/java/cc/fascinated/services/ScoreService.java index 893b31f..ca22ed4 100644 --- a/API/src/main/java/cc/fascinated/services/ScoreService.java +++ b/API/src/main/java/cc/fascinated/services/ScoreService.java @@ -80,36 +80,17 @@ public class ScoreService { */ public PaginationBuilder.Page getTopRankedScores(@NonNull Platform.Platforms platform, int pageNumber, boolean scoresOnly) { PaginationBuilder builder = new PaginationBuilder().build(); - builder.itemsPerPage(50); - builder.fillItems(() -> { - List foundScores = this.scoreRepository.getTopRankedScores(platform, 250); + builder.itemsPerPage(15); + builder.totalItems(() -> this.scoreRepository.getTotalRankedScores(platform)); + builder.items((fetchItems) -> { + List foundScores = this.scoreRepository.getTopRankedScores(platform, fetchItems.getItemsPerPage(), fetchItems.skipAmount()); List scores = new ArrayList<>(); for (Score score : foundScores) { ScoreSaberScore scoreSaberScore = (ScoreSaberScore) score; UserDTO user = scoresOnly ? null : userService.getUser(score.getPlayerId()).getAsDTO(); Leaderboard leaderboard = scoresOnly ? null : Leaderboard.getFromScoreSaberToken(scoreSaberService.getLeaderboard(score.getLeaderboardId())); - scores.add(new ScoreSaberScoreResponse( - score.getId(), - score.getPlayerId(), - score.getPlatform(), - score.getPlatformScoreId(), - score.getLeaderboardId(), - score.getRank(), - score.getAccuracy(), - score.getPp(), - score.getScore(), - score.getModifiers(), - score.getMisses(), - score.getBadCuts(), - score.getDeviceInformation(), - score.getTimestamp(), - scoreSaberScore.getWeight(), - scoreSaberScore.getMultiplier(), - scoreSaberScore.getMaxCombo(), - user, - leaderboard - )); + scores.add(ScoreSaberScoreResponse.fromScore(scoreSaberScore, user, leaderboard)); } return scores; });