2024-11-19 11:32:56 +05:00
|
|
|
|
using Mapster;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
using Persistence.Database.Model;
|
|
|
|
|
using Persistence.Models;
|
|
|
|
|
|
|
|
|
|
namespace Persistence.Repository.Repositories;
|
|
|
|
|
|
|
|
|
|
public class TimeSeriesDataCachedRepository<TEntity, TDto> : TimeSeriesDataRepository<TEntity, TDto>
|
|
|
|
|
where TEntity : class, ITimestampedData, new()
|
|
|
|
|
where TDto : class, ITimeSeriesAbstractDto, new()
|
|
|
|
|
{
|
2024-11-21 17:02:36 +05:00
|
|
|
|
public static TDto? FirstByDate { get; private set; }
|
|
|
|
|
public static CyclicArray<TDto> LastData { get; } = new CyclicArray<TDto>(CacheItemsCount);
|
2024-11-19 11:32:56 +05:00
|
|
|
|
|
2024-11-19 17:51:51 +05:00
|
|
|
|
private const int CacheItemsCount = 3600;
|
|
|
|
|
|
2024-11-19 11:32:56 +05:00
|
|
|
|
public TimeSeriesDataCachedRepository(DbContext db) : base(db)
|
|
|
|
|
{
|
2024-11-19 17:51:51 +05:00
|
|
|
|
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();
|
2024-11-19 11:32:56 +05:00
|
|
|
|
}
|
|
|
|
|
|
2024-11-21 17:02:36 +05:00
|
|
|
|
public override async Task<IEnumerable<TDto>> GetGtDate(DateTimeOffset dateBegin, CancellationToken token)
|
2024-11-19 11:32:56 +05:00
|
|
|
|
{
|
|
|
|
|
|
2024-11-19 17:51:51 +05:00
|
|
|
|
if (LastData.Count() == 0 || LastData[0].Date > dateBegin)
|
2024-11-19 11:32:56 +05:00
|
|
|
|
{
|
2024-11-21 17:02:36 +05:00
|
|
|
|
var dtos = await base.GetGtDate(dateBegin, token);
|
2024-11-19 11:32:56 +05:00
|
|
|
|
return dtos;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-19 17:51:51 +05:00
|
|
|
|
var items = LastData
|
2024-11-21 17:02:36 +05:00
|
|
|
|
.Where(i => i.Date >= dateBegin);
|
2024-11-19 11:32:56 +05:00
|
|
|
|
|
|
|
|
|
return items;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async Task<int> InsertRange(IEnumerable<TDto> dtos, CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
var result = await base.InsertRange(dtos, token);
|
|
|
|
|
if (result > 0)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
dtos = dtos.OrderBy(x => x.Date);
|
|
|
|
|
|
2024-11-19 17:51:51 +05:00
|
|
|
|
FirstByDate = dtos.First();
|
2024-11-19 11:32:56 +05:00
|
|
|
|
LastData.AddRange(dtos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2024-11-21 17:02:36 +05:00
|
|
|
|
|
|
|
|
|
public override async Task<DatesRangeDto?> GetDatesRange(CancellationToken token)
|
|
|
|
|
{
|
|
|
|
|
if (FirstByDate == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
return await Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
return new DatesRangeDto
|
|
|
|
|
{
|
|
|
|
|
From = FirstByDate.Date,
|
|
|
|
|
To = LastData[^1].Date
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}
|
2024-11-22 15:47:00 +05:00
|
|
|
|
|
2024-11-22 16:48:55 +05:00
|
|
|
|
public override async Task<IEnumerable<TDto>> GetResampledData(
|
|
|
|
|
DateTimeOffset dateBegin,
|
|
|
|
|
double intervalSec = 600d,
|
|
|
|
|
int approxPointsCount = 1024,
|
|
|
|
|
CancellationToken token = default)
|
2024-11-22 15:47:00 +05:00
|
|
|
|
{
|
|
|
|
|
var dtos = LastData.Where(i => i.Date >= dateBegin);
|
|
|
|
|
if (LastData.Count == 0 || LastData[0].Date > dateBegin)
|
|
|
|
|
{
|
2024-11-22 16:48:55 +05:00
|
|
|
|
dtos = await base.GetGtDate(dateBegin, token);
|
2024-11-22 15:47:00 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2024-11-19 11:32:56 +05:00
|
|
|
|
}
|
|
|
|
|
|