persistence/Persistence.Repository/Repositories/ChangeLogRepository.cs

260 lines
8.1 KiB
C#

using Mapster;
using Microsoft.EntityFrameworkCore;
using Persistence.Database.Model;
using Persistence.Models;
using Persistence.Models.Requests;
using Persistence.Repositories;
using UuidExtensions;
namespace Persistence.Repository.Repositories;
public class ChangeLogRepository : IChangeLogRepository
{
private DbContext db;
public ChangeLogRepository(DbContext db)
{
this.db = db;
}
public async Task<int> AddRange(Guid idAuthor, int idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
{
var entities = new List<ChangeLog>();
foreach (var dto in dtos)
{
var entity = CreateEntityFromDto(idAuthor, idDiscriminator, dto);
entities.Add(entity);
}
db.Set<ChangeLog>().AddRange(entities);
var result = await db.SaveChangesAsync(token);
return result;
}
public async Task<int> MarkAsDeleted(Guid idEditor, IEnumerable<Guid> ids, CancellationToken token)
{
var query = db.Set<ChangeLog>()
.Where(s => ids.Contains(s.Id))
.Where(s => s.Obsolete == null);
if (query.Count() != ids.Count())
{
throw new ArgumentException("Count of active items not equal count of ids", nameof(ids));
}
var entities = await query.ToArrayAsync(token);
var result = await MarkAsObsolete(idEditor, entities, token);
return result;
}
public async Task<int> MarkAsDeleted(Guid idEditor, int idDiscriminator, CancellationToken token)
{
var query = db.Set<ChangeLog>()
.Where(s => s.IdDiscriminator == idDiscriminator)
.Where(e => e.Obsolete == null);
var entities = await query.ToArrayAsync(token);
var result = await MarkAsObsolete(idEditor, entities, token);
return result;
}
private async Task<int> MarkAsObsolete(Guid idEditor, IEnumerable<ChangeLog> entities, CancellationToken token)
{
var updateTime = DateTimeOffset.UtcNow;
foreach (var entity in entities)
{
entity.Obsolete = updateTime;
entity.IdEditor = idEditor;
}
return await db.SaveChangesAsync(token);
}
public async Task<int> ClearAndAddRange(Guid idAuthor, int idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
{
var result = 0;
using var transaction = await db.Database.BeginTransactionAsync(token);
result += await MarkAsDeleted(idAuthor, idDiscriminator, token);
result += await AddRange(idAuthor, idDiscriminator, dtos, token);
await transaction.CommitAsync(token);
return result;
}
public async Task<int> UpdateRange(Guid idEditor, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
{
var dbSet = db.Set<ChangeLog>();
var updatedIds = dtos.Select(d => d.Id);
var updatedEntities = dbSet
.Where(s => updatedIds.Contains(s.Id))
.ToDictionary(s => s.Id);
var result = 0;
using var transaction = await db.Database.BeginTransactionAsync(token);
foreach (var dto in dtos)
{
var updatedEntity = updatedEntities.GetValueOrDefault(dto.Id);
if (updatedEntity is null)
{
throw new ArgumentException($"Entity with id = {dto.Id} doesn't exist in Db", nameof(dto));
}
var newEntity = CreateEntityFromDto(idEditor, updatedEntity.IdDiscriminator, dto);
dbSet.Add(newEntity);
updatedEntity.IdNext = newEntity.Id;
updatedEntity.Obsolete = DateTimeOffset.UtcNow;
updatedEntity.IdEditor = idEditor;
}
result = await db.SaveChangesAsync(token);
await transaction.CommitAsync(token);
return result;
}
public async Task<PaginationContainer<DataWithWellDepthAndSectionDto>> GetByDate(
int idDiscriminator,
DateTimeOffset momentUtc,
SectionPartRequest filterRequest,
PaginationRequest paginationRequest,
CancellationToken token)
{
var query = CreateQuery(idDiscriminator);
query = query.Apply(momentUtc);
query = query.Apply(filterRequest);
var result = await query.ApplyPagination(paginationRequest, Convert, token);
return result;
}
private IQueryable<ChangeLog> CreateQuery(int idDiscriminator)
{
var query = db.Set<ChangeLog>().Where(e => e.IdDiscriminator == idDiscriminator);
return query;
}
public async Task<IEnumerable<ChangeLogDto>> GetChangeLogForInterval(int idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
{
var query = db.Set<ChangeLog>().Where(s => s.IdDiscriminator == idDiscriminator);
var min = new DateTimeOffset(dateBegin.ToUniversalTime().Date, TimeSpan.Zero);
var max = new DateTimeOffset(dateEnd.ToUniversalTime().Date, TimeSpan.Zero);
var createdQuery = query.Where(e => e.Creation >= min && e.Creation <= max);
var editedQuery = query.Where(e => e.Obsolete != null && e.Obsolete >= min && e.Obsolete <= max);
query = createdQuery.Union(editedQuery);
var entities = await query.ToArrayAsync(token);
var dtos = entities.Select(e => e.Adapt<ChangeLogDto>());
return dtos;
}
public async Task<IEnumerable<DateOnly>> GetDatesChange(int idDiscriminator, CancellationToken token)
{
var query = db.Set<ChangeLog>().Where(e => e.IdDiscriminator == idDiscriminator);
var datesCreateQuery = query
.Select(e => e.Creation)
.Distinct();
var datesCreate = await datesCreateQuery.ToArrayAsync(token);
var datesUpdateQuery = query
.Where(e => e.Obsolete != null)
.Select(e => e.Obsolete!.Value)
.Distinct();
var datesUpdate = await datesUpdateQuery.ToArrayAsync(token);
var dates = Enumerable.Concat(datesCreate, datesUpdate);
var datesOnly = dates
.Select(d => new DateOnly(d.Year, d.Month, d.Day))
.Distinct()
.OrderBy(d => d);
return datesOnly;
}
private ChangeLog CreateEntityFromDto(Guid idAuthor, int idDiscriminator, DataWithWellDepthAndSectionDto dto)
{
var entity = new ChangeLog()
{
Id = Uuid7.Guid(),
Creation = DateTimeOffset.UtcNow,
IdAuthor = idAuthor,
IdDiscriminator = idDiscriminator,
IdEditor = idAuthor,
Value = dto.Value,
IdSection = dto.IdSection,
DepthStart = dto.DepthStart,
DepthEnd = dto.DepthEnd,
};
return entity;
}
public async Task<IEnumerable<DataWithWellDepthAndSectionDto>> GetGtDate(int idDiscriminator, DateTimeOffset dateBegin, CancellationToken token)
{
var date = dateBegin.ToUniversalTime();
var query = this.db.Set<ChangeLog>()
.Where(e => e.IdDiscriminator == idDiscriminator)
.Where(e => e.Creation >= date || e.Obsolete >= date);
var entities = await query.ToArrayAsync(token);
var dtos = entities.Select(Convert);
return dtos;
}
public async Task<DatesRangeDto?> GetDatesRange(int idDiscriminator, CancellationToken token)
{
var query = db.Set<ChangeLog>()
.Where(e => e.IdDiscriminator == idDiscriminator)
.GroupBy(e => 1)
.Select(group => new
{
Min = group.Min(e => e.Creation),
Max = group.Max(e => (e.Obsolete.HasValue && e.Obsolete > e.Creation)
? e.Obsolete.Value
: e.Creation),
});
var values = await query.FirstOrDefaultAsync(token);
if (values is null)
{
return null;
}
return new DatesRangeDto
{
From = values.Min,
To = values.Max,
};
}
private DataWithWellDepthAndSectionDto Convert(ChangeLog entity) => entity.Adapt<DataWithWellDepthAndSectionDto>();
}