using System; using Enyim.Caching; using Expedience.Infrastructure.Models; using Microsoft.EntityFrameworkCore; namespace Expedience.Infrastructure; public interface IExpedienceRepository { ValueTask> GetDutyCompletionRecords(string expac, CancellationToken cancellationToken); ValueTask> GetDeepDungeonRecords(CancellationToken cancellationToken); ValueTask> GetTopXRecords(int recordType, int territoryId, int limit, CancellationToken cancellationToken); } public class ExpedienceRepository : IExpedienceRepository { private readonly ExpedienceContext _dbContext; private readonly IMemcachedClient _memcachedClient; public ExpedienceRepository(ExpedienceContext dbContext, IMemcachedClient memcachedClient) { _dbContext = dbContext; _memcachedClient = memcachedClient; } public async ValueTask> GetDutyCompletionRecords(string expac, CancellationToken cancellationToken) { var cacheKey = $"xpd-dcr-{expac}"; var cacheSeconds = 600; var records = await _memcachedClient.GetValueOrCreateAsync(cacheKey, cacheSeconds, async () => await _dbContext.DutyCompletionRecords.FromSqlInterpolated($"SELECT * FROM public.get_dutycompletionrecords({expac})") .ToListAsync(cancellationToken)); return records; } public async ValueTask> GetDeepDungeonRecords(CancellationToken cancellationToken) { var cacheKey = $"xpd-dd"; var cacheSeconds = 600; var records = await _memcachedClient.GetValueOrCreateAsync(cacheKey, cacheSeconds, async () => await _dbContext.DeepDungeonRecords.FromSqlInterpolated($"SELECT * FROM public.get_deepdungeonresults()") .ToListAsync(cancellationToken)); return records; } public async ValueTask> GetTopXRecords(int recordType, int territoryId, int limit, CancellationToken cancellationToken) { var cacheKey = $"xpd-topx-{recordType}-{territoryId}-{limit}"; var cacheSeconds = 600; var records = await _memcachedClient.GetValueOrCreateAsync(cacheKey, cacheSeconds, async () => { var topXResults = await _dbContext.TopXRecords.FromSqlInterpolated($"SELECT * FROM public.get_topxcompletionresults({recordType}, {territoryId}, {limit})") .ToListAsync(cancellationToken); // Get the IDs we need for our related entities var topXIds = topXResults.Select(r => r.Id).ToList(); var userIds = topXResults.Select(r => r.UserId).Distinct().ToList(); // Then, fetch the related DutyMembers and DutyCompletionResults var dutyMembers = await _dbContext.DutyMembers .Where(dm => topXIds.Contains(dm.UploadId)) .ToListAsync(); var dutyCompletionResults = await _dbContext.DutyCompletionResults .Where(dcr => topXIds.Contains(dcr.Id)) .ToListAsync(); var users = await _dbContext.Users .Where(u => userIds.Contains(u.UserId)) .ToListAsync(); var territory = await _dbContext.Territories .FirstAsync(t => territoryId == t.TerritoryId); // Create TopXCompletionResultFull objects var fullResults = topXResults.Select(result => new TopXCompletionResultFull { TopXResult = result, DutyMembers = dutyMembers.Where(dm => dm.UploadId == result.Id).ToList(), DutyCompletionResult = dutyCompletionResults.First(dcr => dcr.Id == result.Id), User = users.First(u => u.UserId == result.UserId), Territory = territory }).ToList(); return fullResults; }); return records; } }