using AsbCloudApp.Data; using AsbCloudApp.Exceptions; using AsbCloudApp.Services; using AsbCloudDb.Model; using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace AsbCloudInfrastructure.Services; public class MeasureService : IMeasureService { private readonly IAsbCloudDbContext db; private readonly IMemoryCache memoryCache; private readonly IWellService wellService; private static readonly TimeSpan CacheOlescence = TimeSpan.FromMinutes(20); public MeasureService(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService) { this.db = db; this.memoryCache = memoryCache; this.wellService = wellService; } public async Task> GetCategoriesAsync(CancellationToken token) { var key = typeof(MeasureCategory).FullName; var cache = await memoryCache.GetOrCreateAsync(key, async (cacheEntry) => { cacheEntry.AbsoluteExpirationRelativeToNow = CacheOlescence; cacheEntry.SlidingExpiration = CacheOlescence; var entities = await db.Set() .ToDictionaryAsync(e => e.Id, e => e.Name, token); return entities; }); return cache!; } public async Task GetLastOrDefaultAsync(int idWell, int idCategory, CancellationToken token) { var query = db.Measures .Include(m => m.Category) .Where(m => m.IdWell == idWell && m.IdCategory == idCategory && !m.IsDeleted) .OrderByDescending(m => m.Timestamp) .Take(1); var entity = await query .AsNoTracking() .FirstOrDefaultAsync(token) .ConfigureAwait(false); var timezone = wellService.GetTimezone(idWell); if (entity is null) return null; return Convert(entity, timezone.Hours); } public async Task> GetHisoryAsync(int idWell, int? idCategory = null, CancellationToken token = default) { var query = db.Measures.Include(m => m.Category) .Where(m => m.IdWell == idWell && !m.IsDeleted); if (idCategory is not null) query = query.Where(m => m.IdCategory == idCategory); var entities = await query .OrderBy(m => m.Timestamp) .AsNoTracking() .ToListAsync(token) .ConfigureAwait(false); var timezone = wellService.GetTimezone(idWell); var dtos = entities.Select(e => Convert(e, timezone.Hours)); return dtos; } public Task InsertAsync(int idWell, MeasureDto dto, CancellationToken token) { if (dto.IdCategory < 1) throw new ArgumentInvalidException(nameof(dto), "wrong idCategory"); if (!dto.Data.Any()) throw new ArgumentInvalidException(nameof(dto), "data.data is not optional"); var entity = Convert(dto); entity.IdWell = idWell; db.Measures.Add(entity); return db.SaveChangesAsync(token); } public async Task UpdateAsync(int idWell, MeasureDto dto, CancellationToken token) { if (dto.Id < 1) throw new ArgumentInvalidException(nameof(dto), "wrong id"); if (dto.IdCategory < 1) throw new ArgumentInvalidException(nameof(dto), "wrong idCategory"); if (!dto.Data.Any()) throw new ArgumentInvalidException(nameof(dto), "data.data is not optional"); var entity = await db.Measures .Where(m => m.Id == dto.Id && !m.IsDeleted) .FirstOrDefaultAsync(token) ?? throw new ArgumentInvalidException(nameof(dto), "id doesn't exist"); var timezone = wellService.GetTimezone(idWell); entity.IdWell = idWell; entity.Timestamp = dto.Timestamp.ToOffset(TimeSpan.FromHours(timezone.Hours)); entity.Data = dto.Data.Adapt(); return await db.SaveChangesAsync(token).ConfigureAwait(false); } public async Task MarkAsDeleteAsync(int idWell, int idData, CancellationToken token) { if (idData < 1) throw new ArgumentInvalidException(nameof(idData), "wrong id"); var entity = await db.Measures.Where(m => m.IdWell == idWell && m.Id == idData) .FirstOrDefaultAsync(token) ?? throw new ArgumentInvalidException(nameof(idWell), $"Measure doesn't exist"); entity.IsDeleted = true; return await db.SaveChangesAsync(token).ConfigureAwait(false); } public Task DeleteAsync(int idWell, int idData, CancellationToken token) { if (idData < 1) throw new ArgumentInvalidException(nameof(idData), "wrong id"); db.Measures.RemoveRange(db.Measures.Where(m => m.IdWell == idWell && m.Id == idData)); return db.SaveChangesAsync(token); } private MeasureDto Convert(Measure entity, double hours) { var dto = entity.Adapt(); dto.CategoryName = entity.Category?.Name ?? String.Empty; dto.Timestamp = entity.Timestamp.ToOffset(TimeSpan.FromHours(hours)); return dto; } private Measure Convert(MeasureDto dto) { var entity = dto.Adapt(); entity.Timestamp = dto.Timestamp.ToUniversalTime(); return entity; } }