using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json.Linq; using Persistence.Database.Entity; using Persistence.Models; using Persistence.Models.Requests; using Persistence.Repositories; using Persistence.Repository.Extensions; namespace Persistence.Repository.Repositories { public class TechMessagesRepository : ITechMessagesRepository { private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DataSourceSystem).FullName}CacheKey"; private const int CacheExpirationInMinutes = 60; private readonly IMemoryCache memoryCache; private DbContext db; public TechMessagesRepository(DbContext db, IMemoryCache memoryCache) { this.memoryCache = memoryCache; this.db = db; } protected virtual IQueryable GetQueryReadOnly() => db.Set() .Include(e => e.System); public async Task> GetPage(PaginationRequest request, CancellationToken token) { var query = GetQueryReadOnly(); var count = await query.CountAsync(token); var sort = request.SortSettings != string.Empty ? request.SortSettings : nameof(TechMessage.Timestamp); var entities = await query .SortBy(request.SortSettings!) .Skip(request.Skip) .Take(request.Take) .ToArrayAsync(token); var dto = new PaginationContainer() { Skip = request.Skip, Take = request.Take, Count = count, Items = entities.Select(e => e.Adapt()) }; return dto; } public async Task> GetStatistics(IEnumerable systems, IEnumerable categoryIds, CancellationToken token) { var query = GetQueryReadOnly(); var result = await query .Where(e => systems.Count() == 0 || systems.Contains(e.System.SystemId)) .GroupBy(e => e.System.Name, (key, group) => new { System = key, Categories = group .Where(g => categoryIds.Count() == 0 || categoryIds.Contains(g.CategoryId)) }) .ToArrayAsync(token); var entities = new List(); foreach (var e in result) { var categories = e.Categories .GroupBy(g => g.CategoryId) .ToDictionary(c => c.Key, v => v.Count()); var entity = new MessagesStatisticDto() { System = e.System, Categories = categories }; entities.Add(entity); } return entities; } public async Task AddRange(Guid systemId, IEnumerable dtos, Guid userId, CancellationToken token) { var entities = new List(); foreach (var dto in dtos) { var entity = dto.Adapt(); await CreateSystemIfNotExist(systemId, token); entity.SystemId = systemId; entities.Add(entity); } await db.Set().AddRangeAsync(entities, token); var result = await db.SaveChangesAsync(token); return result; } public async Task> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token) { var query = GetQueryReadOnly(); var entities = await query .Where(e => e.Timestamp >= dateBegin) .Take(take) .ToArrayAsync(token); var dtos = entities .Select(e => e.Adapt()); return dtos; } public async Task> GetSystems(CancellationToken token) { var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f => { f.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CacheExpirationInMinutes); var query = db.Set(); var entities = await query.ToListAsync(token); var dtos = entities.Select(e => e.Adapt()); return dtos; }); return systems ?? []; } public async Task GetDatesRangeAsync(CancellationToken token) { var query = GetQueryReadOnly() .GroupBy(e => 1) .Select(group => new { Min = group.Min(e => e.Timestamp), Max = group.Max(e => e.Timestamp), }); var values = await query.FirstOrDefaultAsync(token); var result = new DatesRangeDto() { From = values?.Min ?? DateTimeOffset.MinValue, To = values?.Max ?? DateTimeOffset.MaxValue }; return result; } private async Task CreateSystemIfNotExist(Guid systemId, CancellationToken token) { var systems = await GetSystems(token); var system = systems?.FirstOrDefault(e => e.SystemId == systemId); if (system == null) { system = new DataSourceSystemDto() { SystemId = systemId, Name = string.Empty }; var entity = system.Adapt(); await db.Set().AddAsync(entity); await db.SaveChangesAsync(token); memoryCache.Remove(SystemCacheKey); } } } }