Kavita/Kavita.Database/Repositories/ReadingSessionRepository.cs
Fesaa c62b20f54b
BE Tech Debt (#4497)
Co-authored-by: Joseph Milazzo <joseph.v.milazzo@gmail.com>
Co-authored-by: Joe Milazzo <josephmajora@gmail.com>
2026-03-07 10:04:08 -08:00

83 lines
2.9 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using Kavita.API.Repositories;
using Kavita.Models.DTOs.Progress;
using Microsoft.EntityFrameworkCore;
namespace Kavita.Database.Repositories;
public class ReadingSessionRepository(DataContext context, IMapper mapper) : IReadingSessionRepository
{
public async Task<IList<ReadingSessionDto>> GetAllReadingSessionAsync(bool isActiveOnly = true,
CancellationToken ct = default)
{
var query = context.AppUserReadingSession
.Where(s => !isActiveOnly || s.IsActive);
var sessions = await query
.Include(s => s.ActivityData)
.Include(s => s.AppUser)
.ToListAsync(ct);
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 a parallel - single query per table
var libraryLookupTask = context.Library
.Where(l => libraryIds.Contains(l.Id))
.ToDictionaryAsync(l => l.Id, l => l.Name, ct);
var seriesLookupTask = context.Series
.Where(s => seriesIds.Contains(s.Id))
.ToDictionaryAsync(s => s.Id, s => s.Name, ct);
var chapterLookupTask = context.Chapter
.Where(c => chapterIds.Contains(c.Id))
.ToDictionaryAsync(c => c.Id, c => c.TitleName, ct);
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;
}
}