diff --git a/readme.md b/readme.md index 118d789..766a3a0 100644 --- a/readme.md +++ b/readme.md @@ -124,7 +124,8 @@ flowchart LR moods, the total playtime and moon trips, the drill-down lists) uses the set total, the view `user_game_entry_playtime` (V45), the same as the library card, sort and public profile. So do "played", "never started" and "under one hour": a set counts once, judged by its set total (also the dashboard "never played" and the - oldest unplayed game). Only the nightly trend snapshot `never_played` still uses the counted edition's own minutes. + oldest unplayed game) and the trend's never played (`backlog_snapshot`); rows written before #43 keep the old value, + they cannot be rebuilt. Platforms stay per edition: a Steam + PlayStation set counts on both platforms. - **Drill-down**: every countable number opens the games behind it. A `StatKey` (library), `CommunityKey` (landing page) or a Pile Points track/bonus row names a number; its SQL "game set" is the same text the number counts, so the diff --git a/src/main/java/core_service/modules/library/repo/BacklogSnapshotRepository.java b/src/main/java/core_service/modules/library/repo/BacklogSnapshotRepository.java index 1770c5d..92b99a3 100644 --- a/src/main/java/core_service/modules/library/repo/BacklogSnapshotRepository.java +++ b/src/main/java/core_service/modules/library/repo/BacklogSnapshotRepository.java @@ -12,6 +12,7 @@ import java.util.List; /** * The daily pile size per user, table backlog_snapshot. Counts listed games only, like {@link UserGameRepository#LISTED}, and a linked set once (V28). + * Never played is judged by the set total (V45), like {@link UserGameRepository#countListedNeverPlayed}. */ @Repository @RequiredArgsConstructor @@ -19,11 +20,12 @@ public class BacklogSnapshotRepository { private static final String PILE_COLUMNS = """ count(*) filter (where ug.status = 'BACKLOG' and cg.appid is null) as backlog_games, - count(*) filter (where ug.playtime_minutes = 0) as never_played, + count(*) filter (where ep.playtime_minutes = 0) as never_played, coalesce(sum(t.normally_minutes) filter (where ug.status = 'BACKLOG' and cg.appid is null), 0) as backlog_minutes, count(*) as listed_games from counted_user_game ug left join game_time_to_beat t on t.appid = ug.appid left join coming_game cg on cg.appid = ug.appid + left join user_game_entry_playtime ep on ep.user_id = ug.user_id and ep.appid = ug.appid """; private final NamedParameterJdbcTemplate jdbc; diff --git a/src/test/java/core_service/modules/library/repo/BacklogSnapshotRepositoryTest.java b/src/test/java/core_service/modules/library/repo/BacklogSnapshotRepositoryTest.java index 3ae0229..552f6a8 100644 --- a/src/test/java/core_service/modules/library/repo/BacklogSnapshotRepositoryTest.java +++ b/src/test/java/core_service/modules/library/repo/BacklogSnapshotRepositoryTest.java @@ -86,6 +86,30 @@ class BacklogSnapshotRepositoryTest extends AbstractPersistenceTest { assertThat(repository.findSince(1L, DAY)).containsExactly(new UserStats.PileDay(DAY, 1, 1, 600)); } + private void psnPlay(long appid, int minutes) { + jdbc.update("insert into user_psn_title (user_id, psn_key, state, appid, platform, playtime_minutes) " + + "values (1, ?, 'STEAM_OWNED', ?, 'PS5', ?)", "c" + appid, appid, minutes); + } + + @Test + void writeAll_ASetPlayedOnlyOnPlayStationIsNotNeverPlayed() { + userGameRepository.saveAllAndFlush(List.of(game(1L, 220L, 0, GameStatus.BACKLOG), game(1L, 620L, 0, GameStatus.BACKLOG))); + psnPlay(220L, 120); + + repository.writeAll(DAY); + + assertThat(repository.findSince(1L, DAY)).extracting(UserStats.PileDay::neverPlayed).containsExactly(1L); + assertThat(userGameRepository.countListedNeverPlayed(1L)).isEqualTo(1); + } + + @Test + void live_UsesTheSetTotal() { + userGameRepository.saveAllAndFlush(List.of(game(1L, 220L, 0, GameStatus.BACKLOG), game(1L, 620L, 0, GameStatus.BACKLOG))); + psnPlay(220L, 120); + + assertThat(repository.live(1L, DAY).neverPlayed()).isEqualTo(1).isEqualTo(userGameRepository.countListedNeverPlayed(1L)); + } + @Test void writeAll_SecondRunOnTheSameDay_ReplacesTheRow() { UserGame game = game(1L, 220L, 0, GameStatus.BACKLOG);