using System; using Enyim.Caching; using Expedience.Infrastructure.Models; using Expedience.Models; using Microsoft.EntityFrameworkCore; namespace Expedience.Infrastructure; public interface IExpedienceRepository { ValueTask> GetDutyCompletionRecords(string expac, CancellationToken cancellationToken); ValueTask> GetDeepDungeonRecords(CancellationToken cancellationToken); ValueTask> GetContentTypeRecords(string contentType, 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); if (topXResults.Count == 0) return new List(); var topXIds = topXResults.Select(r => r.Id).ToList(); var userIds = topXResults.Select(r => r.UserId).Distinct().ToList(); var dutyCompletionResults = await _dbContext.DutyCompletionResults .Where(dcr => topXIds.Contains(dcr.Id)) .ToListAsync(); var dutyMembers = await _dbContext.DutyMembers .Where(dm => topXIds.Contains(dm.UploadId)) .ToListAsync(); var users = await _dbContext.Users .Where(u => userIds.Contains(u.UserId)) .ToListAsync(); var territory = await _dbContext.Territories .FirstAsync(t => t.TerritoryId == territoryId); var territoryDto = new TerritoryDto { TerritoryId = territory.TerritoryId, PlaceName = territory.PlaceName, ContentName = territory.ContentName, Level = territory.Level, ContentType = territory.ContentType, Expac = territory.Expac }; var resultDtos = topXResults.Select(result => new TopXCompletionResultDto { Rank = result.Rank, Duration = result.Duration, DutyCompletionResult = dutyCompletionResults .Where(dcr => dcr.Id == result.Id) .Select(dcr => new DutyCompletionResultDto { Id = dcr.Id, UserId = dcr.UserId, TerritoryId = dcr.TerritoryId, HasEcho = dcr.HasEcho, IsUnrestricted = dcr.IsUnrestricted, IsMinILevel = dcr.IsMinILevel, HasNpcMembers = dcr.HasNpcMembers, StartTime = dcr.StartTime, EndTime = dcr.EndTime, Hours = dcr.Hours, Minutes = dcr.Minutes, Seconds = dcr.Seconds, Milliseconds = dcr.Milliseconds, GameVersion = dcr.GameVersion, PluginVersion = dcr.PluginVersion, Lang = dcr.Lang, DataCenter = dcr.DataCenter, UploadedAt = dcr.UploadedAt }).First(), DutyMembers = dutyMembers .Where(dm => dm.UploadId == result.Id) .Select(dm => new DutyMemberDto { UploadId = dm.UploadId, GroupNumber = dm.GroupNumber, MemberNumber = dm.MemberNumber, Level = dm.Level, ClassJob = dm.ClassJob, IsNpc = dm.IsNpc, IsPlayer = dm.IsPlayer, }).ToList(), User = users .Where(u => u.UserId == result.UserId) .Select(u => new UserDto { UserId = u.UserId, UserName = u.UserName, WorldId = u.WorldId }).FirstOrDefault(), Territory = territoryDto }).ToList(); return resultDtos; }); return records; } public async ValueTask> GetContentTypeRecords(string contentType, CancellationToken cancellationToken) { var cacheKey = $"xpd-th"; var cacheSeconds = 600; var records = await _memcachedClient.GetValueOrCreateAsync(cacheKey, cacheSeconds, async () => await _dbContext.ContentTypeRecords.FromSqlInterpolated($"SELECT * FROM public.get_contenttyperesults({contentType})") .ToListAsync(cancellationToken)); return records; } }