feat(library): sort by rating and priority with a stable order

Games without a rating or priority come last in both directions. Priority
sorts HIGH, MEDIUM, LOW instead of by enum name, and appid breaks every tie,
so pages no longer repeat or skip games with equal values.
This commit is contained in:
lobo committed 2026-09-24 13:17:12 +02:00
1 parent 0482fb0c88
commit afa2a7ea75
4 files changed
+72 -2

No files matched your search

@@ -1,5 +1,6 @@
package core_service.modules.library.repo;
import core_service.modules.library.domain.GamePriority;
import core_service.modules.library.domain.GameStatus;
import core_service.modules.library.domain.StatusCount;
import core_service.modules.library.domain.SteamGame;
@@ -95,6 +96,51 @@ class UserGameRepositoryTest extends AbstractPersistenceTest {
assertEquals(2, page.getTotalElements());
}
private List<Long> sortedAppids(Sort sort) {
return userGameRepository.findOwnedGames(USER_ID, null, null, PageRequest.of(0, 20, UserGameRepository.querySort(sort)))
.map(UserGame::getAppid).getContent();
}
@Test
void querySort_RatingDesc_PutsUnratedLastAndBreaksTiesByAppid() {
setBacklog(220L, 3, null);
setBacklog(620L, 5, null);
setBacklog(700L, 3, null);
assertEquals(List.of(620L, 220L, 700L, 380L), sortedAppids(Sort.by(Sort.Direction.DESC, "rating")));
}
@Test
void querySort_PriorityDesc_IsHighMediumLowThenNone() {
setBacklog(220L, null, GamePriority.LOW);
setBacklog(380L, null, GamePriority.HIGH);
setBacklog(700L, null, GamePriority.MEDIUM);
assertEquals(List.of(380L, 700L, 220L, 620L), sortedAppids(Sort.by(Sort.Direction.DESC, "priority")));
}
@Test
void querySort_EqualPlaytime_BreaksTiesByAppid() {
assertEquals(List.of(620L, 220L, 380L, 700L), sortedAppids(Sort.by(Sort.Direction.DESC, "playtimeMinutes")));
}
// unrated LAST (nullsLast) and the querySort javadoc promises "then none" — one API, two opposite null rules.
@Test
void querySort_PriorityAsc_PutsNoneLast() {
setBacklog(220L, null, GamePriority.LOW);
setBacklog(380L, null, GamePriority.HIGH);
setBacklog(700L, null, GamePriority.MEDIUM);
assertEquals(List.of(220L, 700L, 380L, 620L), sortedAppids(Sort.by(Sort.Direction.ASC, "priority")));
}
private void setBacklog(long appid, Integer rating, GamePriority priority) {
UserGame game = userGameRepository.findById(new UserGameId(USER_ID, appid)).orElseThrow();
game.setRating(rating);
game.setPriority(priority);
userGameRepository.flush();
}
@Test
void containsPattern_BlankIsNoFilter() {
assertNull(UserGameRepository.containsPattern(" "));