using Mapster; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; using Persistence.Database.Model; using Persistence.Models; namespace Persistence.Repository.Repositories; public class TimeSeriesDataCachedRepository : TimeSeriesDataRepository where TEntity : class, ITimestampedData, new() where TDto : class, ITimeSeriesAbstractDto, new() { public static TDto? FirstByDate { get; private set; } public static CyclicArray LastData { get; } = new CyclicArray(CacheItemsCount); private const int CacheItemsCount = 3600; public TimeSeriesDataCachedRepository(DbContext db) : base(db) { Task.Run(async () => { var firstDateItem = await base.GetFirstAsync(CancellationToken.None); if (firstDateItem == null) { return; } FirstByDate = firstDateItem; var dtos = await base.GetLastAsync(CacheItemsCount, CancellationToken.None); dtos = dtos.OrderBy(d => d.Date); LastData.AddRange(dtos); }).Wait(); } public override async Task> GetGtDate(DateTimeOffset dateBegin, CancellationToken token) { if (LastData.Count() == 0 || LastData[0].Date > dateBegin) { var dtos = await base.GetGtDate(dateBegin, token); return dtos; } var items = LastData .Where(i => i.Date >= dateBegin); return items; } public override async Task InsertRange(IEnumerable dtos, CancellationToken token) { var result = await base.InsertRange(dtos, token); if (result > 0) { dtos = dtos.OrderBy(x => x.Date); FirstByDate = dtos.First(); LastData.AddRange(dtos); } return result; } public override async Task GetDatesRange(CancellationToken token) { if (FirstByDate == null) return null; return await Task.Run(() => { return new DatesRangeDto { From = FirstByDate.Date, To = LastData[^1].Date }; }); } public override async Task> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024) { var dtos = LastData.Where(i => i.Date >= dateBegin); if (LastData.Count == 0 || LastData[0].Date > dateBegin) { dtos = await base.GetGtDate(dateBegin, CancellationToken.None); } var dateEnd = dateBegin.AddSeconds(intervalSec); dtos = dtos .Where(i => i.Date <= dateEnd); var ratio = dtos.Count() / approxPointsCount; if (ratio > 1) dtos = dtos .Where((_, index) => index % ratio == 0); return dtos; } }