Kavita/API/Data/Repositories/ReadingSessionRepository.cs
Joe Milazzo 988b6f8c8d
Even More Polish (#4340)
Co-authored-by: Amelia <77553571+Fesaa@users.noreply.github.com>
Co-authored-by: Weblate (bot) <hosted@weblate.org>
Co-authored-by: Adam Havránek <adamhavra@seznam.cz>
Co-authored-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
Co-authored-by: Dark77 <Dark77@pobox.sk>
Co-authored-by: Frozehunter <frozehunter@me.com>
Co-authored-by: Havokdan <havokdan@yahoo.com.br>
Co-authored-by: Igor Dobrača <igor.dobraca@gmail.com>
Co-authored-by: Karl B <karl.owl@proton.me>
Co-authored-by: Morhain Olivier <sesram@users.noreply.hosted.weblate.org>
Co-authored-by: daydreamrabbit <devrabbit90@gmail.com>
Co-authored-by: karigane <169052233+karigane-cha@users.noreply.github.com>
Co-authored-by: oxygen44k <iiccpp@outlook.com>
Co-authored-by: Максим Горпиніч <gorpinicmaksim0@gmail.com>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Co-authored-by: 안세훈 <on9686@gmail.com>
2026-01-11 11:01:54 -08:00

85 lines
2.9 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using API.DTOs.Progress;
using AutoMapper;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
public interface IReadingSessionRepository
{
Task<IList<ReadingSessionDto>> GetAllReadingSessionAsync(bool isActiveOnly = true);
}
public class ReadingSessionRepository(DataContext context, IMapper mapper) : IReadingSessionRepository
{
public async Task<IList<ReadingSessionDto>> GetAllReadingSessionAsync(bool isActiveOnly = true)
{
var query = context.AppUserReadingSession
.Where(s => !isActiveOnly || s.IsActive);
var sessions = await query
.Include(s => s.ActivityData)
.Include(s => s.AppUser)
.ToListAsync();
if (sessions.Count == 0) return [];
// Gather all unique IDs across ALL sessions
var allActivityData = sessions
.Where(s => s.ActivityData != null)
.SelectMany(s => s.ActivityData)
.ToList();
var libraryIds = allActivityData.Select(a => a.LibraryId).Distinct().ToList();
var seriesIds = allActivityData.Select(a => a.SeriesId).Distinct().ToList();
var chapterIds = allActivityData.Select(a => a.ChapterId).Distinct().ToList();
// Fetch all lookups in parallel - single query per table
var libraryLookupTask = context.Library
.Where(l => libraryIds.Contains(l.Id))
.ToDictionaryAsync(l => l.Id, l => l.Name);
var seriesLookupTask = context.Series
.Where(s => seriesIds.Contains(s.Id))
.ToDictionaryAsync(s => s.Id, s => s.Name);
var chapterLookupTask = context.Chapter
.Where(c => chapterIds.Contains(c.Id))
.ToDictionaryAsync(c => c.Id, c => c.TitleName);
await Task.WhenAll(libraryLookupTask, seriesLookupTask, chapterLookupTask);
var libraryLookup = libraryLookupTask.Result;
var seriesLookup = seriesLookupTask.Result;
var chapterLookup = chapterLookupTask.Result;
// Map all sessions with AutoMapper
var dtos = mapper.Map<List<ReadingSessionDto>>(sessions);
// Enrich all activity data with names
foreach (var dto in dtos)
{
if (dto.ActivityData == null) continue;
// Sort by most recent first
dto.ActivityData = dto.ActivityData
.OrderByDescending(a => a.EndTimeUtc)
.ToList();
// First activity data will be the most recent
foreach (var activity in dto.ActivityData)
{
activity.LibraryName = libraryLookup.GetValueOrDefault(activity.LibraryId, string.Empty);
activity.SeriesName = seriesLookup.GetValueOrDefault(activity.SeriesId, string.Empty);
activity.ChapterTitle = chapterLookup.GetValueOrDefault(activity.ChapterId, string.Empty);
}
}
return dtos;
}
}