Добавить таблицу для учета комментариев и действий пользователя для вывода статистики по ChangeLog #30
@ -1,107 +1,124 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using DD.Persistence.API;
|
||||
using DD.Persistence.API.Services;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Requests;
|
||||
using DD.Persistence.Repositories;
|
||||
using System.Net;
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.Models.Requests;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Net;
|
||||
using UuidExtensions;
|
||||
|
||||
namespace DD.Persistence.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Контроллер по работе с журналом изменений
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
[Route("api/[controller]")]
|
||||
|
||||
public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
{
|
||||
private readonly IChangeLogRepository repository;
|
||||
private ChangeLogService service { get; }
|
||||
|
||||
public ChangeLogController(IChangeLogRepository repository)
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="service"></param>
|
||||
public ChangeLogController(ChangeLogService service)
|
||||
ng.frolov
commented
Должен остаться только один Должен остаться только один
|
||||
{
|
||||
this.repository = repository;
|
||||
this.service = service;
|
||||
ng.frolov
commented
Было бы здорова дать методам контроллеров текстовое описание для сваггера. Было бы здорова дать методам контроллеров текстовое описание для сваггера.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавить записи в журнал изменений по дискриминатору
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
ng.frolov
commented
Скорее всего этот метод лишний. Скорее всего этот метод лишний.
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||
public async Task<IActionResult> Add(
|
||||
[FromRoute] Guid idDiscriminator,
|
||||
[FromBody] ChangeLogValuesDto dto,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
var result = await repository.AddRange(userId, idDiscriminator, [dto], token);
|
||||
|
||||
return CreatedAtAction(nameof(Add), result);
|
||||
}
|
||||
|
||||
[HttpPost("range/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||
public async Task<IActionResult> AddRange(
|
||||
[FromRoute] Guid idDiscriminator,
|
||||
[FromBody] IEnumerable<ChangeLogValuesDto> dtos,
|
||||
string comment,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
var result = await repository.AddRange(userId, idDiscriminator, dtos, token);
|
||||
var changeLogCommitRequest = new CreateChangeLogCommitRequest(Uuid7.Guid(), comment);
|
||||
var result = await service.AddRange(idDiscriminator, changeLogCommitRequest, dtos, token);
|
||||
|
||||
return CreatedAtAction(nameof(AddRange), result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удалить записи в журнале изменений
|
||||
/// </summary>
|
||||
ng.frolov
commented
Скорее всего в ChangeLogCommitDto dtos - лишнее, и помешаются в методе delete например. Скорее всего в ChangeLogCommitDto dtos - лишнее, и помешаются в методе delete например.
Отношение строчек с данными к коммиту делается уже внутри сервиса.
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken token)
|
||||
public async Task<IActionResult> DeleteRange(IEnumerable<Guid> ids, string comment, CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
var result = await repository.MarkAsDeleted(userId, [id], token);
|
||||
var changeLogCommitRequest = new CreateChangeLogCommitRequest(userId, comment);
|
||||
var result = await service.MarkAsDeleted(ids, changeLogCommitRequest, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete("range")]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> DeleteRange(IEnumerable<Guid> ids, CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
var result = await repository.MarkAsDeleted(userId, ids, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Очистить все записи в журнале изменений (по дискриминатору) и добавить новые
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("replace/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> ClearAndAddRange(
|
||||
[FromRoute] Guid idDiscriminator,
|
||||
[FromBody] IEnumerable<ChangeLogValuesDto> dtos,
|
||||
string comment,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
var result = await repository.ClearAndAddRange(userId, idDiscriminator, dtos, token);
|
||||
var changeLogCommitRequest = new CreateChangeLogCommitRequest(userId, comment);
|
||||
var result = await service.ClearAndAddRange(idDiscriminator, changeLogCommitRequest, dtos, token);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// сохранить изменения в записях журнала изменений
|
||||
/// </summary>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPut]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> Update(
|
||||
ChangeLogValuesDto dto,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
var result = await repository.UpdateRange(userId, [dto], token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPut("range")]
|
||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> UpdateRange(
|
||||
IEnumerable<ChangeLogValuesDto> dtos,
|
||||
string comment,
|
||||
CancellationToken token)
|
||||
{
|
||||
var userId = User.GetUserId<Guid>();
|
||||
var result = await repository.UpdateRange(userId, dtos, token);
|
||||
var changeLogCommitRequest = new CreateChangeLogCommitRequest(userId, comment);
|
||||
var result = await service.UpdateRange(changeLogCommitRequest, dtos, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение актуальных записей (с пагинацией)
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="paginationRequest"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(PaginationContainer<ChangeLogValuesDto>), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetCurrent(
|
||||
@ -110,11 +127,19 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
CancellationToken token)
|
||||
{
|
||||
var moment = new DateTimeOffset(3000, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
var result = await repository.GetByDate(idDiscriminator, moment, paginationRequest, token);
|
||||
var result = await service.GetByDate(idDiscriminator, moment, paginationRequest, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение записей на определенный момент времени (с пагинацией)
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="moment"></param>
|
||||
/// <param name="paginationRequest"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("moment/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(PaginationContainer<ChangeLogValuesDto>), (int)HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetByDate(
|
||||
@ -123,11 +148,19 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
[FromQuery] PaginationRequest paginationRequest,
|
||||
CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetByDate(idDiscriminator, moment, paginationRequest, token);
|
||||
var result = await service.GetByDate(idDiscriminator, moment, paginationRequest, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение измененных записей за период времени
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dateBegin"></param>
|
||||
/// <param name="dateEnd"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("history/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(IEnumerable<ChangeLogDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
@ -137,37 +170,57 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
||||
DateTimeOffset dateEnd,
|
||||
CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, token);
|
||||
var result = await service.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("datesChange/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(IEnumerable<DateOnly>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<IActionResult> GetDatesChange([FromRoute] Guid idDiscriminator, CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetDatesChange(idDiscriminator, token);
|
||||
var result = await service.GetDatesChange(idDiscriminator, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных, начиная с определенной даты
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dateBegin"></param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("part/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(IEnumerable<ChangeLogValuesDto>), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<ActionResult<IEnumerable<ChangeLogValuesDto>>> GetPart([FromRoute] Guid idDiscriminator, DateTimeOffset dateBegin, int take = 86400, CancellationToken token = default)
|
||||
{
|
||||
var result = await repository.GetGtDate(idDiscriminator, dateBegin, token);
|
||||
var result = await service.GetGtDate(idDiscriminator, dateBegin, token);
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("datesRange/{idDiscriminator}")]
|
||||
[ProducesResponseType(typeof(DatesRangeDto), (int)HttpStatusCode.OK)]
|
||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||
public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync([FromRoute] Guid idDiscriminator, CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetDatesRange(idDiscriminator, token);
|
||||
var result = await service.GetDatesRange(idDiscriminator, token);
|
||||
|
||||
if (result is null)
|
||||
return NoContent();
|
||||
|
@ -9,6 +9,8 @@ using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Nodes;
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.API.Services;
|
||||
|
||||
namespace DD.Persistence.API;
|
||||
|
||||
@ -53,6 +55,7 @@ public static class DependencyInjection
|
||||
{
|
||||
services.AddTransient<IWitsDataService, WitsDataService>();
|
||||
services.AddTransient<ITimestampedValuesService, TimestampedValuesService>();
|
||||
services.AddTransient<ChangeLogService>();
|
||||
}
|
||||
|
||||
#region Authentication
|
||||
|
198
DD.Persistence.API/Services/ChangeLogService.cs
Normal file
@ -0,0 +1,198 @@
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Requests;
|
||||
using DD.Persistence.Repositories;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using DD.Persistence.Database.Entity;
|
||||
|
||||
namespace DD.Persistence.API.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Сервис по работе с журналом изменений
|
||||
/// </summary>
|
||||
public class ChangeLogService
|
||||
{
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly IChangeLogCommitRepository commitRepository;
|
||||
private readonly IChangeLogRepository repository;
|
||||
private readonly TimeSpan? AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60);
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="memoryCache"></param>
|
||||
/// <param name="commitRepository"></param>
|
||||
/// <param name="repository"></param>
|
||||
public ChangeLogService(
|
||||
IMemoryCache memoryCache,
|
||||
IChangeLogCommitRepository commitRepository,
|
||||
IChangeLogRepository repository)
|
||||
{
|
||||
this.memoryCache = memoryCache;
|
||||
this.commitRepository = commitRepository;
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Чтение ключа коммита из кеша или (если коммита в кеше нет) создание коммита
|
||||
ng.frolov
commented
Тут мы не читаем данные коммита. Только получаем его Id. Тут мы не читаем данные коммита. Только получаем его Id.
Не правильное название и описание.
|
||||
/// </summary>
|
||||
/// <param name="commitDto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<Guid> GetOrCreateCommitAsync(CreateChangeLogCommitRequest commitDto, CancellationToken token)
|
||||
ng.frolov
commented
Давай в кеше хранить комит целиком не только ID Давай в кеше хранить комит целиком не только ID
|
||||
{
|
||||
var key = (commitDto.IdAuthor, commitDto.Comment);
|
||||
var commitId = await memoryCache.GetOrCreateAsync(key, async (cacheEntry) =>
|
||||
{
|
||||
cacheEntry.AbsoluteExpirationRelativeToNow = AbsoluteExpirationRelativeToNow;
|
||||
|
||||
var commitId = await commitRepository.Add(commitDto, token);
|
||||
|
||||
return commitId;
|
||||
});
|
||||
return commitId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавление записи в журнал изменений
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="commitRequestDto"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> AddRange(Guid idDiscriminator, CreateChangeLogCommitRequest commitRequestDto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var commitId = await GetOrCreateCommitAsync(commitRequestDto, token);
|
||||
var commitDto = new ChangeLogCommitDto(commitId, commitRequestDto);
|
||||
|
||||
var result = await repository.AddRange(idDiscriminator, commitDto, dtos, token);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Пометить запись журнала изменений как удаленную
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="commitRequestDto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> MarkAsDeleted(IEnumerable<Guid> ids, CreateChangeLogCommitRequest commitRequestDto, CancellationToken token)
|
||||
{
|
||||
var commitId = await GetOrCreateCommitAsync(commitRequestDto, token);
|
||||
var commitDto = new ChangeLogCommitDto(commitId, commitRequestDto);
|
||||
|
||||
var result = await repository.MarkAsDeleted(commitId, ids, commitDto.Creation, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Очистить старые и добавить новые записи в журнал изменений
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="commitRequestDto"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> ClearAndAddRange(Guid idDiscriminator, CreateChangeLogCommitRequest commitRequestDto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var commitId = await GetOrCreateCommitAsync(commitRequestDto, token);
|
||||
var commitDto = new ChangeLogCommitDto(commitId, commitRequestDto);
|
||||
|
||||
var result = await repository.ClearAndAddRange(idDiscriminator, commitDto, dtos, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновить записи в журнале изменений
|
||||
/// </summary>
|
||||
/// <param name="commitRequestDto"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> UpdateRange(CreateChangeLogCommitRequest commitRequestDto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var commitId = await GetOrCreateCommitAsync(commitRequestDto, token);
|
||||
var commitDto = new ChangeLogCommitDto(commitId, commitRequestDto);
|
||||
|
||||
var result = await repository.UpdateRange(commitDto, dtos, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение актуальных записей на определенный момент времени (с пагинацией)
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="momentUtc"></param>
|
||||
/// <param name="paginationRequest"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<PaginationContainer<ChangeLogValuesDto>> GetByDate(
|
||||
Guid idDiscriminator,
|
||||
DateTimeOffset momentUtc,
|
||||
PaginationRequest paginationRequest,
|
||||
CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetByDate(idDiscriminator, momentUtc, paginationRequest, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение измененных записей за период времени
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dateBegin"></param>
|
||||
/// <param name="dateEnd"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<ChangeLogDto>> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<DateOnly>> GetDatesChange(Guid idDiscriminator, CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetDatesChange(idDiscriminator, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить данные, начиная с определенной даты
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dateBegin"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<ChangeLogValuesDto>> GetGtDate(Guid idDiscriminator, DateTimeOffset dateBegin, CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetGtDate(idDiscriminator, dateBegin, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token)
|
||||
{
|
||||
var result = await repository.GetDatesRange(idDiscriminator, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -19,10 +19,10 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token)
|
||||
{
|
||||
var result = await ExecuteGetResponse(
|
||||
async () => await refitChangeLogClient.ClearAndAddRange(idDiscriminator, dtos, token), token);
|
||||
async () => await refitChangeLogClient.ClearAndAddRange(idDiscriminator, dtos, comment, token), token);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -47,55 +47,28 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token)
|
||||
public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.Add(idDiscriminator, dto, token), token);
|
||||
async () => await refitChangeLogClient.AddRange(idDiscriminator, dtos, comment, token), token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.AddRange(idDiscriminator, dtos, token), token);
|
||||
async () => await refitChangeLogClient.UpdateRange(dtos, comment, token), token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> Update(ChangeLogValuesDto dto, CancellationToken token)
|
||||
public async Task<int> DeleteRange(IEnumerable<Guid> ids, string comment, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.Update(dto, token), token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.UpdateRange(dtos, token), token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> Delete(Guid id, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.Delete(id, token), token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> DeleteRange(IEnumerable<Guid> ids, CancellationToken token)
|
||||
{
|
||||
var result = await ExecutePostResponse(
|
||||
async () => await refitChangeLogClient.DeleteRange(ids, token), token);
|
||||
async () => await refitChangeLogClient.DeleteRange(ids, comment, token), token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -9,48 +9,34 @@ namespace DD.Persistence.Client.Clients.Interfaces;
|
||||
/// </summary>
|
||||
public interface IChangeLogClient : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Добавить одну запись
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить несколько записей
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<int> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Импорт с заменой: удаление старых строк и добавление новых
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить одну запись
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> Delete(Guid id, CancellationToken token);
|
||||
Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить несколько записей
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> DeleteRange(IEnumerable<Guid> ids, CancellationToken token);
|
||||
Task<int> DeleteRange(IEnumerable<Guid> ids, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение актуальных данных на определенную дату (с пагинацией)
|
||||
@ -80,19 +66,12 @@ public interface IChangeLogClient : IDisposable
|
||||
/// <returns></returns>
|
||||
Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить одну запись
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> Update(ChangeLogValuesDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить несколько записей
|
||||
/// </summary>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<int> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
}
|
@ -16,7 +16,7 @@ public interface IRefitChangeLogClient : IRefitClient, IDisposable
|
||||
/// Импорт с заменой: удаление старых строк и добавление новых
|
||||
/// </summary>
|
||||
[Post($"{BaseRoute}/replace/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<int>> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<IApiResponse<int>> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение актуальных данных на определенную дату (с пагинацией)
|
||||
@ -34,41 +34,23 @@ public interface IRefitChangeLogClient : IRefitClient, IDisposable
|
||||
[Get($"{BaseRoute}/history/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<IEnumerable<ChangeLogDto>>> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить одну запись
|
||||
/// </summary>
|
||||
[Post($"{BaseRoute}/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<int>> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить несколько записей
|
||||
/// </summary>
|
||||
[Post($"{BaseRoute}/range/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<int>> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить одну запись
|
||||
/// </summary>
|
||||
[Put($"{BaseRoute}")]
|
||||
Task<IApiResponse<int>> Update(ChangeLogValuesDto dto, CancellationToken token);
|
||||
[Post($"{BaseRoute}/{{idDiscriminator}}")]
|
||||
Task<IApiResponse<int>> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить несколько записей
|
||||
/// </summary>
|
||||
[Put($"{BaseRoute}/range")]
|
||||
Task<IApiResponse<int>> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить одну запись
|
||||
/// </summary>
|
||||
[Delete($"{BaseRoute}")]
|
||||
Task<IApiResponse<int>> Delete(Guid id, CancellationToken token);
|
||||
[Put($"{BaseRoute}")]
|
||||
Task<IApiResponse<int>> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить несколько записей
|
||||
/// </summary>
|
||||
[Delete($"{BaseRoute}/range")]
|
||||
Task<IApiResponse<int>> DeleteRange([Body] IEnumerable<Guid> ids, CancellationToken token);
|
||||
[Delete($"{BaseRoute}")]
|
||||
Task<IApiResponse<int>> DeleteRange([Body] IEnumerable<Guid> ids, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
|
||||
|
@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
namespace DD.Persistence.Database.Postgres.Migrations
|
||||
{
|
||||
[DbContext(typeof(PersistencePostgresContext))]
|
||||
[Migration("20250210055116_Init")]
|
||||
[Migration("20250221053248_Init")]
|
||||
partial class Init
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@ -41,18 +41,18 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Дискриминатор таблицы");
|
||||
|
||||
b.Property<Guid>("IdAuthor")
|
||||
b.Property<Guid>("IdCreatedCommit")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Автор изменения");
|
||||
|
||||
b.Property<Guid?>("IdEditor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Редактор");
|
||||
.HasComment("Id коммита на создание записи");
|
||||
|
||||
b.Property<Guid?>("IdNext")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id заменяющей записи");
|
||||
|
||||
b.Property<Guid?>("IdObsoletedCommit")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id коммита на устаревание записи");
|
||||
|
||||
b.Property<DateTimeOffset?>("Obsolete")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата устаревания (например при удалении)");
|
||||
@ -64,9 +64,38 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IdCreatedCommit");
|
||||
|
||||
b.HasIndex("IdObsoletedCommit");
|
||||
|
||||
b.ToTable("change_log");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.ChangeLogCommit", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id коммита");
|
||||
|
||||
b.Property<string>("Comment")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasComment("Комментарий к коммиту");
|
||||
|
||||
b.Property<DateTimeOffset>("Creation")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания коммита");
|
||||
|
||||
b.Property<Guid>("IdAuthor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Пользователь, создавший коммит");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("change_log_commit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
|
||||
{
|
||||
b.Property<Guid>("SystemId")
|
||||
@ -214,6 +243,23 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
b.ToTable("timestamped_values");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.ChangeLog", b =>
|
||||
{
|
||||
b.HasOne("DD.Persistence.Database.Entity.ChangeLogCommit", "CreatedCommit")
|
||||
.WithMany("ChangeLogCreatedItems")
|
||||
.HasForeignKey("IdCreatedCommit")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("DD.Persistence.Database.Entity.ChangeLogCommit", "ObsoletedCommit")
|
||||
.WithMany("ChangeLogObsoletedItems")
|
||||
.HasForeignKey("IdObsoletedCommit");
|
||||
|
||||
b.Navigation("CreatedCommit");
|
||||
|
||||
b.Navigation("ObsoletedCommit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
|
||||
{
|
||||
b.HasOne("DD.Persistence.Database.Entity.DataSourceSystem", "System")
|
||||
@ -224,6 +270,13 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
b.Navigation("System");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.ChangeLogCommit", b =>
|
||||
{
|
||||
b.Navigation("ChangeLogCreatedItems");
|
||||
|
||||
b.Navigation("ChangeLogObsoletedItems");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
@ -13,21 +13,17 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "change_log",
|
||||
name: "change_log_commit",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ записи"),
|
||||
DiscriminatorId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"),
|
||||
IdAuthor = table.Column<Guid>(type: "uuid", nullable: false, comment: "Автор изменения"),
|
||||
IdEditor = table.Column<Guid>(type: "uuid", nullable: true, comment: "Редактор"),
|
||||
Creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата создания записи"),
|
||||
Obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true, comment: "Дата устаревания (например при удалении)"),
|
||||
IdNext = table.Column<Guid>(type: "uuid", nullable: true, comment: "Id заменяющей записи"),
|
||||
Value = table.Column<string>(type: "jsonb", nullable: false, comment: "Значение")
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id коммита"),
|
||||
IdAuthor = table.Column<Guid>(type: "uuid", nullable: false, comment: "Пользователь, создавший коммит"),
|
||||
Creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата создания коммита"),
|
||||
Comment = table.Column<string>(type: "text", nullable: false, comment: "Комментарий к коммиту")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_change_log", x => x.Id);
|
||||
table.PrimaryKey("PK_change_log_commit", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
@ -98,6 +94,35 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
table.PrimaryKey("PK_timestamped_values", x => new { x.DiscriminatorId, x.Timestamp });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "change_log",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ записи"),
|
||||
DiscriminatorId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"),
|
||||
Creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата создания записи"),
|
||||
Obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true, comment: "Дата устаревания (например при удалении)"),
|
||||
IdNext = table.Column<Guid>(type: "uuid", nullable: true, comment: "Id заменяющей записи"),
|
||||
Value = table.Column<string>(type: "jsonb", nullable: false, comment: "Значение"),
|
||||
IdCreatedCommit = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id коммита на создание записи"),
|
||||
IdObsoletedCommit = table.Column<Guid>(type: "uuid", nullable: true, comment: "Id коммита на устаревание записи")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_change_log", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_change_log_change_log_commit_IdCreatedCommit",
|
||||
column: x => x.IdCreatedCommit,
|
||||
principalTable: "change_log_commit",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_change_log_change_log_commit_IdObsoletedCommit",
|
||||
column: x => x.IdObsoletedCommit,
|
||||
principalTable: "change_log_commit",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "tech_message",
|
||||
columns: table => new
|
||||
@ -120,6 +145,16 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_change_log_IdCreatedCommit",
|
||||
table: "change_log",
|
||||
column: "IdCreatedCommit");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_change_log_IdObsoletedCommit",
|
||||
table: "change_log",
|
||||
column: "IdObsoletedCommit");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_tech_message_SystemId",
|
||||
table: "tech_message",
|
||||
@ -147,6 +182,9 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
migrationBuilder.DropTable(
|
||||
name: "timestamped_values");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "change_log_commit");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "data_source_system");
|
||||
}
|
@ -38,18 +38,18 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Дискриминатор таблицы");
|
||||
|
||||
b.Property<Guid>("IdAuthor")
|
||||
b.Property<Guid>("IdCreatedCommit")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Автор изменения");
|
||||
|
||||
b.Property<Guid?>("IdEditor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Редактор");
|
||||
.HasComment("Id коммита на создание записи");
|
||||
|
||||
b.Property<Guid?>("IdNext")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id заменяющей записи");
|
||||
|
||||
b.Property<Guid?>("IdObsoletedCommit")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id коммита на устаревание записи");
|
||||
|
||||
b.Property<DateTimeOffset?>("Obsolete")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата устаревания (например при удалении)");
|
||||
@ -61,9 +61,38 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IdCreatedCommit");
|
||||
|
||||
b.HasIndex("IdObsoletedCommit");
|
||||
|
||||
b.ToTable("change_log");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.ChangeLogCommit", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id коммита");
|
||||
|
||||
b.Property<string>("Comment")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasComment("Комментарий к коммиту");
|
||||
|
||||
b.Property<DateTimeOffset>("Creation")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата создания коммита");
|
||||
|
||||
b.Property<Guid>("IdAuthor")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Пользователь, создавший коммит");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("change_log_commit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
|
||||
{
|
||||
b.Property<Guid>("SystemId")
|
||||
@ -211,6 +240,23 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
b.ToTable("timestamped_values");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.ChangeLog", b =>
|
||||
{
|
||||
b.HasOne("DD.Persistence.Database.Entity.ChangeLogCommit", "CreatedCommit")
|
||||
.WithMany("ChangeLogCreatedItems")
|
||||
.HasForeignKey("IdCreatedCommit")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("DD.Persistence.Database.Entity.ChangeLogCommit", "ObsoletedCommit")
|
||||
.WithMany("ChangeLogObsoletedItems")
|
||||
.HasForeignKey("IdObsoletedCommit");
|
||||
|
||||
b.Navigation("CreatedCommit");
|
||||
|
||||
b.Navigation("ObsoletedCommit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TechMessage", b =>
|
||||
{
|
||||
b.HasOne("DD.Persistence.Database.Entity.DataSourceSystem", "System")
|
||||
@ -221,6 +267,13 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
||||
|
||||
b.Navigation("System");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DD.Persistence.Database.Entity.ChangeLogCommit", b =>
|
||||
{
|
||||
b.Navigation("ChangeLogCreatedItems");
|
||||
|
||||
b.Navigation("ChangeLogObsoletedItems");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ public static class DependencyInjection
|
||||
//services.AddTransient(typeof(PersistenceRepository<TimestampedValues>));
|
||||
|
||||
services.AddTransient<ISetpointRepository, SetpointRepository>();
|
||||
services.AddTransient<IChangeLogCommitRepository, ChangeLogCommitRepository>();
|
||||
services.AddTransient<IChangeLogRepository, ChangeLogRepository>();
|
||||
services.AddTransient<ITimestampedValuesRepository, TimestampedValuesRepository>();
|
||||
services.AddTransient<ITechMessagesRepository, TechMessagesRepository>();
|
||||
|
@ -19,12 +19,6 @@ public class ChangeLog : IDiscriminatorItem, IChangeLog
|
||||
[Comment("Дискриминатор таблицы")]
|
||||
public Guid DiscriminatorId { get; set; }
|
||||
|
||||
[Comment("Автор изменения")]
|
||||
public Guid IdAuthor { get; set; }
|
||||
|
||||
[Comment("Редактор")]
|
||||
public Guid? IdEditor { get; set; }
|
||||
|
||||
[Comment("Дата создания записи")]
|
||||
public DateTimeOffset Creation { get; set; }
|
||||
ng.frolov
commented
Комментарий про денормализацию БД Комментарий про денормализацию БД
|
||||
|
||||
@ -36,4 +30,16 @@ public class ChangeLog : IDiscriminatorItem, IChangeLog
|
||||
|
||||
[Column(TypeName = "jsonb"), Comment("Значение")]
|
||||
public required IDictionary<string, object> Value { get; set; }
|
||||
|
||||
[Required, Comment("Id коммита на создание записи")]
|
||||
public Guid IdCreatedCommit { get; set; }
|
||||
|
||||
[Comment("Id коммита на устаревание записи")]
|
||||
public Guid? IdObsoletedCommit { get; set; }
|
||||
ng.frolov
commented
Для устаревших записей у нас есть 2 коммита: один при создании записи и еще один при устаревании. Для устаревших записей у нас есть 2 коммита: один при создании записи и еще один при устаревании.
Кстати туда же можно унести инфо о пользователях и датах.
|
||||
|
||||
[Required, ForeignKey(nameof(IdCreatedCommit)), Comment("Коммит пользователя на создание записи")]
|
||||
public virtual ChangeLogCommit CreatedCommit { get; set; } = null!;
|
||||
|
||||
[ForeignKey(nameof(IdObsoletedCommit)), Comment("Коммит пользователя на устаревание записи")]
|
||||
public virtual ChangeLogCommit? ObsoletedCommit { get; set; }
|
||||
}
|
||||
|
35
DD.Persistence.Database/Entity/ChangeLogCommit.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DD.Persistence.Database.Entity;
|
||||
|
||||
/// <summary>
|
||||
/// Таблица c коммитами пользователей
|
||||
/// </summary>
|
||||
[Table("change_log_commit")]
|
||||
public class ChangeLogCommit
|
||||
{
|
||||
[Key, Comment("Id коммита")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[Comment("Пользователь, создавший коммит")]
|
||||
public Guid IdAuthor { get; set; }
|
||||
|
||||
[Comment("Дата создания коммита")]
|
||||
public DateTimeOffset Creation { get; set; }
|
||||
|
||||
[Comment("Комментарий к коммиту")]
|
||||
public required string Comment { get; set; }
|
||||
|
||||
[Required, InverseProperty(nameof(ChangeLog.CreatedCommit)), Comment("Записи, добавленные в журнал изменений")]
|
||||
public virtual ICollection<ChangeLog> ChangeLogCreatedItems { get; set; } = null!;
|
||||
|
||||
[InverseProperty(nameof(ChangeLog.ObsoletedCommit)), Comment("Устаревшие записи в журнале изменений")]
|
||||
public virtual ICollection<ChangeLog>? ChangeLogObsoletedItems { get; set; } = null!;
|
||||
}
|
@ -10,16 +10,6 @@ public interface IChangeLog
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Автор изменения
|
||||
/// </summary>
|
||||
public Guid IdAuthor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Редактор
|
||||
/// </summary>
|
||||
public Guid? IdEditor { get; set; }
|
||||
ng.frolov
commented
Свойства не должны быть реализованы в интерфейсе. Свойства не должны быть реализованы в интерфейсе.
А почему автор коммита устаревания удален, а автор коммита создания нет?
|
||||
|
||||
/// <summary>
|
||||
/// Дата создания записи
|
||||
/// </summary>
|
||||
|
@ -16,6 +16,8 @@ public class PersistenceDbContext : DbContext
|
||||
|
||||
public DbSet<ChangeLog> ChangeLog => Set<ChangeLog>();
|
||||
|
||||
public DbSet<ChangeLogCommit> ChangeLogCommit => Set<ChangeLogCommit>();
|
||||
|
||||
public DbSet<TechMessage> TechMessage => Set<TechMessage>();
|
||||
|
||||
public DbSet<ParameterData> ParameterData => Set<ParameterData>();
|
||||
|
@ -0,0 +1,39 @@
|
||||
using DD.Persistence.Database.Entity;
|
||||
using DD.Persistence.Models.Requests;
|
||||
using DD.Persistence.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UuidExtensions;
|
||||
|
||||
namespace DD.Persistence.Database.Repositories;
|
||||
public class ChangeLogCommitRepository : IChangeLogCommitRepository
|
||||
{
|
||||
private DbContext db;
|
||||
|
||||
public ChangeLogCommitRepository(DbContext db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<Guid> Add(CreateChangeLogCommitRequest commitRequestDto, CancellationToken token)
|
||||
ng.frolov
commented
commitRequestDto -> commitRequest или request commitRequestDto -> commitRequest или request
|
||||
{
|
||||
|
||||
var commit = new ChangeLogCommit()
|
||||
{
|
||||
Id = Uuid7.Guid(),
|
||||
IdAuthor = commitRequestDto.IdAuthor,
|
||||
Comment = commitRequestDto.Comment,
|
||||
Creation = commitRequestDto.Creation,
|
||||
};
|
||||
|
||||
db.Add(commit);
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
return commit.Id;
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ using DD.Persistence.Models.Requests;
|
||||
using DD.Persistence.Repositories;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using UuidExtensions;
|
||||
|
||||
namespace DD.Persistence.Database.Repositories;
|
||||
@ -18,12 +19,20 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<int> AddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> AddRange(Guid idDiscriminator, ChangeLogCommitDto commitDto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var entities = new List<ChangeLog>();
|
||||
foreach (var dto in dtos)
|
||||
foreach (var values in dtos)
|
||||
{
|
||||
var entity = CreateEntityFromDto(idAuthor, idDiscriminator, dto);
|
||||
var entity = new ChangeLog()
|
||||
{
|
||||
Id = Uuid7.Guid(),
|
||||
Creation = commitDto.Creation,
|
||||
DiscriminatorId = idDiscriminator,
|
||||
Value = values.Value,
|
||||
IdCreatedCommit = commitDto.Id,
|
||||
};
|
||||
|
||||
entities.Add(entity);
|
||||
}
|
||||
db.Set<ChangeLog>().AddRange(entities);
|
||||
@ -33,7 +42,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> MarkAsDeleted(Guid idEditor, IEnumerable<Guid> ids, CancellationToken token)
|
||||
public async Task<int> MarkAsDeleted(Guid idCommit, IEnumerable<Guid> ids, DateTimeOffset updateTime, CancellationToken token)
|
||||
ng.frolov
commented
Как будто и idCommit и updateTime есть в ChangeLogCommitDto Как будто и idCommit и updateTime есть в ChangeLogCommitDto
|
||||
{
|
||||
var query = db.Set<ChangeLog>()
|
||||
.Where(s => ids.Contains(s.Id))
|
||||
@ -46,12 +55,16 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
|
||||
var result = await MarkAsObsolete(idEditor, entities, token);
|
||||
|
||||
return result;
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
entity.Obsolete = updateTime;
|
||||
entity.IdObsoletedCommit = idCommit;
|
||||
}
|
||||
|
||||
public async Task<int> MarkAsDeleted(Guid idEditor, Guid idDiscriminator, CancellationToken token)
|
||||
return await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
public async Task<int> MarkAsDeleted(Guid idDiscriminator, Guid idCommit, DateTimeOffset updateTime, CancellationToken token)
|
||||
{
|
||||
var query = db.Set<ChangeLog>()
|
||||
.Where(s => s.DiscriminatorId == idDiscriminator)
|
||||
@ -59,40 +72,34 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
|
||||
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;
|
||||
entity.DiscriminatorId = idCommit;
|
||||
}
|
||||
|
||||
return await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
public async Task<int> ClearAndAddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
|
||||
public async Task<int> ClearAndAddRange(Guid idDiscriminator, ChangeLogCommitDto commitDto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
ng.frolov
commented
Этот метод должен помечать все записи относящиеся к дискриминатору как удаленные и добавлять новые. Этот метод должен помечать все записи относящиеся к дискриминатору как удаленные и добавлять новые.
|
||||
var result = 0;
|
||||
|
||||
var changeLogIds = dtos.Select(c => c.Id);
|
||||
var comment = commitDto.Comment;
|
||||
ng.frolov
commented
эта логкальная переменная дальше нигде не используется. Зачем она здесь? эта логкальная переменная дальше нигде не используется. Зачем она здесь?
|
||||
|
||||
using var transaction = await db.Database.BeginTransactionAsync(token);
|
||||
|
||||
result += await MarkAsDeleted(idAuthor, idDiscriminator, token);
|
||||
result += await AddRange(idAuthor, idDiscriminator, dtos, token);
|
||||
result += await MarkAsDeleted(commitDto.Id, changeLogIds, commitDto.Creation, token);
|
||||
ng.frolov
commented
Это не то. // arrange Это не то.
Покрой этот метод интеграционным тестом плиз.
// arrange
add some data winth 2 discriminators
// act replace data for 1 discriminaqtor
// assert
check thar othe data with othe discr
|
||||
result += await AddRange(idDiscriminator, commitDto, dtos, token);
|
||||
|
||||
await transaction.CommitAsync(token);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> UpdateRange(Guid idEditor, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
public async Task<int> UpdateRange(ChangeLogCommitDto commitDto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token)
|
||||
{
|
||||
var dbSet = db.Set<ChangeLog>();
|
||||
|
||||
@ -101,7 +108,6 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
.Where(s => updatedIds.Contains(s.Id))
|
||||
.ToDictionary(s => s.Id);
|
||||
|
||||
ng.frolov
commented
Linq очень не оптимально материализует в словари.
Linq очень не оптимально материализует в словари.
Тут лучше материализовать сперва в массив, а затем массив в словарь.
+ Используй асинхронные методы материализации в асинхронных методах репозиториев
|
||||
var result = 0;
|
||||
using var transaction = await db.Database.BeginTransactionAsync(token);
|
||||
|
||||
foreach (var dto in dtos)
|
||||
@ -112,20 +118,25 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
throw new ArgumentException($"Entity with id = {dto.Id} doesn't exist in Db", nameof(dto));
|
||||
}
|
||||
|
||||
var newEntity = CreateEntityFromDto(idEditor, updatedEntity.DiscriminatorId, dto);
|
||||
var newEntity = new ChangeLog()
|
||||
{
|
||||
Id = Uuid7.Guid(),
|
||||
Creation = commitDto.Creation,
|
||||
DiscriminatorId = updatedEntity.DiscriminatorId,
|
||||
Value = dto.Value,
|
||||
IdCreatedCommit = commitDto.Id,
|
||||
};
|
||||
dbSet.Add(newEntity);
|
||||
|
||||
updatedEntity.IdNext = newEntity.Id;
|
||||
updatedEntity.Obsolete = DateTimeOffset.UtcNow;
|
||||
updatedEntity.IdEditor = idEditor;
|
||||
updatedEntity.Obsolete = commitDto.Creation;
|
||||
updatedEntity.IdObsoletedCommit = commitDto.Id;
|
||||
}
|
||||
|
||||
result = await db.SaveChangesAsync(token);
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
await transaction.CommitAsync(token);
|
||||
|
||||
return result;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public async Task<PaginationContainer<ChangeLogValuesDto>> GetByDate(
|
||||
@ -195,22 +206,6 @@ public class ChangeLogRepository : IChangeLogRepository
|
||||
return datesOnly;
|
||||
}
|
||||
|
||||
private static ChangeLog CreateEntityFromDto(Guid idAuthor, Guid idDiscriminator, ChangeLogValuesDto dto)
|
||||
{
|
||||
var entity = new ChangeLog()
|
||||
{
|
||||
Id = Uuid7.Guid(),
|
||||
Creation = DateTimeOffset.UtcNow,
|
||||
IdAuthor = idAuthor,
|
||||
DiscriminatorId = idDiscriminator,
|
||||
IdEditor = idAuthor,
|
||||
|
||||
Value = dto.Value
|
||||
};
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ChangeLogValuesDto>> GetGtDate(Guid idDiscriminator, DateTimeOffset dateBegin, CancellationToken token)
|
||||
{
|
||||
var date = dateBegin.ToUniversalTime();
|
||||
|
@ -15,6 +15,7 @@ namespace DD.Persistence.IntegrationTests.Controllers;
|
||||
public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
{
|
||||
private readonly IChangeLogClient client;
|
||||
private readonly PaginationRequest paginationRequest;
|
||||
private static readonly Random generatorRandomDigits = new();
|
||||
|
||||
public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||
@ -25,22 +26,13 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
|
||||
client = scope.ServiceProvider
|
||||
.GetRequiredService<IChangeLogClient>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClearAndInsertRange_InEmptyDb()
|
||||
paginationRequest = new PaginationRequest()
|
||||
{
|
||||
// arrange
|
||||
dbContext.CleanupDbSet<ChangeLog>();
|
||||
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(2);
|
||||
|
||||
// act
|
||||
var result = await client.ClearAndAddRange(idDiscriminator, dtos, new CancellationToken());
|
||||
|
||||
// assert
|
||||
Assert.Equal(2, result);
|
||||
Skip = 0,
|
||||
Take = 10,
|
||||
SortSettings = String.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -48,33 +40,17 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
{
|
||||
// arrange
|
||||
var insertedCount = 10;
|
||||
var createdResult = CreateChangeLogItems(insertedCount, (-15, 15));
|
||||
var idDiscriminator = createdResult.Item1;
|
||||
var dtos = createdResult.Item2.Select(e => e.Adapt<ChangeLogValuesDto>());
|
||||
var newEntitiesData = await CreateAndReturnNewDtos(insertedCount, (-15, -1));
|
||||
var idDiscriminator = newEntitiesData.Item1;
|
||||
var dtos = newEntitiesData.Item2;
|
||||
|
||||
//act
|
||||
var result = await client.ClearAndAddRange(idDiscriminator, dtos, new CancellationToken());
|
||||
var result = await client.ClearAndAddRange(idDiscriminator, dtos, "Добавление новых элементов и очистка старых", CancellationToken.None);
|
||||
|
||||
// assert
|
||||
Assert.Equal(insertedCount * 2, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Add_returns_success()
|
||||
{
|
||||
// arrange
|
||||
var count = 1;
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(count);
|
||||
var dto = dtos.FirstOrDefault()!;
|
||||
|
||||
// act
|
||||
var result = await client.Add(idDiscriminator, dto, new CancellationToken());
|
||||
|
||||
// assert
|
||||
Assert.Equal(count, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddRange_returns_success()
|
||||
{
|
||||
@ -82,9 +58,10 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
var count = 3;
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(count);
|
||||
var comment = "Создаю 3 элемента";
|
||||
|
||||
// act
|
||||
var result = await client.AddRange(idDiscriminator, dtos, new CancellationToken());
|
||||
var result = await client.AddRange(idDiscriminator, dtos, comment, CancellationToken.None);
|
||||
|
||||
// assert
|
||||
Assert.Equal(count, result);
|
||||
@ -99,7 +76,8 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(1);
|
||||
var dto = dtos.FirstOrDefault()!;
|
||||
var result = await client.Add(idDiscriminator, dto, new CancellationToken());
|
||||
var comment = "Создаю 1 элемент";
|
||||
var result = await client.AddRange(idDiscriminator, [dto], comment, CancellationToken.None);
|
||||
|
||||
var entity = dbContext.ChangeLog
|
||||
.Where(x => x.DiscriminatorId == idDiscriminator)
|
||||
@ -107,7 +85,8 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
dto = entity.Adapt<ChangeLogValuesDto>();
|
||||
|
||||
// act
|
||||
result = await client.Update(dto, new CancellationToken());
|
||||
comment = "Обновляю 1 элемент";
|
||||
result = await client.UpdateRange([dto], comment, CancellationToken.None);
|
||||
|
||||
// assert
|
||||
Assert.Equal(2, result);
|
||||
@ -139,71 +118,49 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
[Fact]
|
||||
public async Task UpdateRange_returns_success()
|
||||
{
|
||||
// arrange
|
||||
var count = 2;
|
||||
var idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(count);
|
||||
var entities = dtos.Select(d => d.Adapt<ChangeLog>()).ToArray();
|
||||
dbContext.ChangeLog.AddRange(entities);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
dtos = entities.Select(c => new ChangeLogValuesDto()
|
||||
{
|
||||
Id = c.Id,
|
||||
Value = c.Value
|
||||
}).ToArray();
|
||||
var comment = "Создаю 3 элемента";
|
||||
|
||||
// act
|
||||
var result = await client.UpdateRange(dtos, new CancellationToken());
|
||||
var result = await client.AddRange(idDiscriminator, dtos, comment, CancellationToken.None);
|
||||
var paginatedResult = await client.GetByDate(idDiscriminator, DateTimeOffset.UtcNow.AddDays(1), paginationRequest, CancellationToken.None);
|
||||
// act
|
||||
comment = "Обновляю 3 элемента";
|
||||
result = await client.UpdateRange(paginatedResult.Items, comment, CancellationToken.None);
|
||||
|
||||
// assert
|
||||
Assert.Equal(count * 2, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Delete_returns_success()
|
||||
{
|
||||
// arrange
|
||||
var dtos = Generate(1);
|
||||
var dto = dtos.FirstOrDefault()!;
|
||||
var entity = dto.Adapt<ChangeLog>();
|
||||
dbContext.ChangeLog.Add(entity);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
// act
|
||||
var result = await client.Delete(entity.Id, new CancellationToken());
|
||||
|
||||
// assert
|
||||
Assert.Equal(1, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteRange_returns_success()
|
||||
{
|
||||
// arrange
|
||||
var count = 10;
|
||||
var dtos = Generate(count);
|
||||
var entities = dtos.Select(d => d.Adapt<ChangeLog>()).ToArray();
|
||||
dbContext.ChangeLog.AddRange(entities);
|
||||
dbContext.SaveChanges();
|
||||
var insertedCount = 10;
|
||||
var newEntitiesData = await CreateAndReturnNewDtos(insertedCount, (-15, -1));
|
||||
var idDiscriminator = newEntitiesData.Item1;
|
||||
var dtos = newEntitiesData.Item2;
|
||||
|
||||
// act
|
||||
var ids = entities.Select(e => e.Id);
|
||||
var result = await client.DeleteRange(ids, new CancellationToken());
|
||||
var ids = dtos.Select(e => e.Id);
|
||||
var result = await client.DeleteRange(ids, "Удаление нескольких записей", CancellationToken.None);
|
||||
|
||||
// assert
|
||||
Assert.Equal(count, result);
|
||||
Assert.Equal(insertedCount, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDatesRange_returns_success()
|
||||
{
|
||||
//arrange
|
||||
var changeLogItems = CreateChangeLogItems(3, (-15, 15));
|
||||
var changeLogItems = await CreateAndReturnNewEntities(3, (-15, -1));
|
||||
var idDiscriminator = changeLogItems.Item1;
|
||||
var entities = changeLogItems.Item2.OrderBy(e => e.Creation);
|
||||
var entities = changeLogItems.Item2.OrderBy(c => c.Creation);
|
||||
|
||||
// act
|
||||
var result = await client.GetDatesRange(idDiscriminator, new CancellationToken());
|
||||
var result = await client.GetDatesRange(idDiscriminator, CancellationToken.None);
|
||||
|
||||
// assert
|
||||
Assert.NotNull(result);
|
||||
@ -228,7 +185,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
|
||||
//создаем записи
|
||||
var count = 5;
|
||||
var changeLogItems = CreateChangeLogItems(count, (-15, 15));
|
||||
var changeLogItems = await CreateAndReturnNewDtos(count, (-15, -1));
|
||||
var idDiscriminator = changeLogItems.Item1;
|
||||
var entities = changeLogItems.Item2;
|
||||
|
||||
@ -237,14 +194,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
var ids = entities.Select(e => e.Id);
|
||||
var idsToDelete = ids.Skip(2);
|
||||
|
||||
var deletedCount = await client.DeleteRange(idsToDelete, new CancellationToken());
|
||||
|
||||
var paginationRequest = new PaginationRequest()
|
||||
{
|
||||
Skip = 0,
|
||||
Take = 10,
|
||||
SortSettings = String.Empty,
|
||||
};
|
||||
var deletedCount = await client.DeleteRange(idsToDelete, "Удаление нескольких записей", CancellationToken.None);
|
||||
|
||||
var moment = DateTimeOffset.UtcNow.AddDays(16);
|
||||
var result = await client.GetByDate(idDiscriminator, moment, paginationRequest, new CancellationToken());
|
||||
@ -260,8 +210,8 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(5, -15, 15, -20, 20, 10)]
|
||||
[InlineData(5, -15, -10, -16, -9, 5)]
|
||||
[InlineData(5, -15, -5, -20, 20, 10)]
|
||||
[InlineData(5, -15, -10, -16, 9, 10)]
|
||||
public async Task GetChangeLogForInterval_returns_success(
|
||||
int insertedCount,
|
||||
int daysBeforeNowChangeLog,
|
||||
@ -276,17 +226,16 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
//создаем записи
|
||||
var count = insertedCount;
|
||||
var daysRange = (daysBeforeNowChangeLog, daysAfterNowChangeLog);
|
||||
var changeLogItems = CreateChangeLogItems(count, daysRange);
|
||||
var changeLogItems = await CreateAndReturnNewDtos(count, daysRange);
|
||||
var idDiscriminator = changeLogItems.Item1;
|
||||
var entities = changeLogItems.Item2;
|
||||
var dtos = changeLogItems.Item2;
|
||||
|
||||
var dtos = entities.Select(e => e.Adapt<ChangeLogValuesDto>()).ToArray();
|
||||
await client.UpdateRange(dtos, new CancellationToken());
|
||||
await client.UpdateRange(dtos, "Обновляем несколько записей", CancellationToken.None);
|
||||
|
||||
//act
|
||||
var dateBegin = DateTimeOffset.UtcNow.AddDays(daysBeforeNowFilter);
|
||||
var dateEnd = DateTimeOffset.UtcNow.AddDays(daysAfterNowFilter);
|
||||
var result = await client.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, new CancellationToken());
|
||||
var result = await client.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
Assert.NotNull(result);
|
||||
@ -308,7 +257,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
|
||||
}
|
||||
|
||||
private (Guid, ChangeLog[]) CreateChangeLogItems(int count, (int, int) daysRange)
|
||||
private async Task<(Guid, IEnumerable<ChangeLogValuesDto>)> CreateAndReturnNewDtos(int count, (int, int) daysRange)
|
||||
{
|
||||
var minDayCount = daysRange.Item1;
|
||||
var maxDayCount = daysRange.Item2;
|
||||
@ -323,8 +272,43 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
||||
|
||||
return entity;
|
||||
}).ToArray();
|
||||
|
||||
dtos = entities.Select(e => e.Adapt<ChangeLogValuesDto>());
|
||||
|
||||
// act
|
||||
var result = await client.AddRange(idDiscriminator, dtos, "Добавление элементов", CancellationToken.None);
|
||||
var paginatedResult = await client.GetByDate(idDiscriminator, DateTimeOffset.UtcNow.AddDays(1), paginationRequest, CancellationToken.None);
|
||||
return (idDiscriminator, paginatedResult.Items);
|
||||
}
|
||||
|
||||
private async Task<(Guid, IEnumerable<ChangeLog>)> CreateAndReturnNewEntities(int count, (int, int) daysRange)
|
||||
{
|
||||
var commit = new ChangeLogCommit()
|
||||
{
|
||||
Comment = "Комментарий к коммиту",
|
||||
Creation = DateTimeOffset.UtcNow,
|
||||
Id = Guid.NewGuid(),
|
||||
};
|
||||
dbContext.ChangeLogCommit.Add(commit);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
var minDayCount = daysRange.Item1;
|
||||
var maxDayCount = daysRange.Item2;
|
||||
|
||||
Guid idDiscriminator = Guid.NewGuid();
|
||||
var dtos = Generate(count);
|
||||
var entities = dtos.Select(d =>
|
||||
{
|
||||
var entity = d.Adapt<ChangeLog>();
|
||||
entity.DiscriminatorId = idDiscriminator;
|
||||
entity.Creation = DateTimeOffset.UtcNow.AddDays(generatorRandomDigits.Next(minDayCount, maxDayCount));
|
||||
entity.IdCreatedCommit = commit.Id;
|
||||
|
||||
return entity;
|
||||
}).ToArray();
|
||||
|
||||
dbContext.ChangeLog.AddRange(entities);
|
||||
dbContext.SaveChanges();
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return (idDiscriminator, entities);
|
||||
}
|
||||
|
21
DD.Persistence.Models/ChangeLogCommitDto.cs
Normal file
@ -0,0 +1,21 @@
|
||||
namespace DD.Persistence.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Модель коммита с изменениями
|
||||
/// </summary>
|
||||
public class ChangeLogCommitDto : CreateChangeLogCommitRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public ChangeLogCommitDto(Guid id, CreateChangeLogCommitRequest request) : base(request.IdAuthor, request.Comment)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
namespace DD.Persistence.Models.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Модель для создания коммита
|
||||
/// </summary>
|
||||
public class CreateChangeLogCommitRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Дата создания
|
||||
/// </summary>
|
||||
public DateTimeOffset Creation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Пользователь, совершающий коммит
|
||||
/// </summary>
|
||||
public Guid IdAuthor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Комментарий
|
||||
/// </summary>
|
||||
public string Comment { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public CreateChangeLogCommitRequest(Guid idAuthor, string comment)
|
||||
{
|
||||
IdAuthor = idAuthor;
|
||||
Comment = comment;
|
||||
Creation = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
}
|
@ -11,8 +11,8 @@
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="Shouldly" Version="4.2.1" />
|
||||
<PackageReference Include="Testcontainers" Version="4.1.0" />
|
||||
<PackageReference Include="Testcontainers.PostgreSql" Version="4.1.0" />
|
||||
<PackageReference Include="Testcontainers" Version="4.2.0" />
|
||||
<PackageReference Include="Testcontainers.PostgreSql" Version="4.2.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.extensibility.core" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
|
279
DD.Persistence.Test/ChangeLogTest.cs
Normal file
@ -0,0 +1,279 @@
|
||||
using DD.Persistence.API.Services;
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.Models.Requests;
|
||||
using DD.Persistence.Repositories;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using NSubstitute;
|
||||
using UuidExtensions;
|
||||
|
||||
namespace DD.Persistence.Test;
|
||||
public class ChangeLogTest
|
||||
{
|
||||
private readonly IChangeLogCommitRepository changeLogCommitRepository = Substitute.For<IChangeLogCommitRepository>();
|
||||
private readonly IChangeLogRepository changeLogRepository = Substitute.For<IChangeLogRepository>();
|
||||
private ChangeLogService service;
|
||||
|
||||
public ChangeLogTest()
|
||||
{
|
||||
var memoryCache = new MemoryCache(new MemoryCacheOptions());
|
||||
service = new ChangeLogService(memoryCache, changeLogCommitRepository, changeLogRepository);
|
||||
}
|
||||
[Fact]
|
||||
public async Task AddRange()
|
||||
{
|
||||
//arrange
|
||||
ng.frolov
commented
Расставь пож. во всех тестах комментарии "//act" и "//assert" чтобы было понятнее где подготовительные операции, где проверяемое действие и где начинаются проверки Расставь пож. во всех тестах комментарии "//act" и "//assert" чтобы было понятнее где подготовительные операции, где проверяемое действие и где начинаются проверки
|
||||
var discriminatorId = Uuid7.Guid();
|
||||
var expectedCommitId = Uuid7.Guid();
|
||||
var comment = "Добавление нескольких значений";
|
||||
var commitRequest = new CreateChangeLogCommitRequest(Uuid7.Guid(), comment);
|
||||
var commit = new ChangeLogCommitDto(expectedCommitId, commitRequest);
|
||||
var dtos = GenerateChangeLogValuesDto(2);
|
||||
|
||||
changeLogCommitRepository.Add(Arg.Any<CreateChangeLogCommitRequest>(), Arg.Any<CancellationToken>()).Returns(Uuid7.Guid());
|
||||
changeLogRepository
|
||||
.AddRange(
|
||||
Arg.Any<Guid>(),
|
||||
Arg.Any<ChangeLogCommitDto>(),
|
||||
Arg.Any<IEnumerable<ChangeLogValuesDto>>(),
|
||||
Arg.Any<CancellationToken>())
|
||||
.Returns(2);
|
||||
|
||||
//act
|
||||
var addRangeResult = await service
|
||||
.AddRange(discriminatorId, commitRequest, dtos, CancellationToken.None);
|
||||
addRangeResult = await service
|
||||
.AddRange(discriminatorId, commitRequest, dtos, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await changeLogCommitRepository.Received(1).Add(commitRequest, CancellationToken.None);
|
||||
await changeLogRepository.Received(2).AddRange(discriminatorId, Arg.Any<ChangeLogCommitDto>(), dtos, CancellationToken.None);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateRange()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Uuid7.Guid();
|
||||
var expectedCommitId = Uuid7.Guid();
|
||||
var comment = "Изменение нескольких значений";
|
||||
var commitRequest = new CreateChangeLogCommitRequest(Uuid7.Guid(), comment);
|
||||
var commit = new ChangeLogCommitDto(expectedCommitId, commitRequest);
|
||||
|
||||
var dtos = GenerateChangeLogValuesDto(2);
|
||||
|
||||
changeLogCommitRepository.Add(Arg.Any<CreateChangeLogCommitRequest>(), Arg.Any<CancellationToken>()).Returns(commit.Id);
|
||||
|
||||
changeLogRepository
|
||||
.UpdateRange(
|
||||
Arg.Any<ChangeLogCommitDto>(),
|
||||
Arg.Any<IEnumerable<ChangeLogValuesDto>>(),
|
||||
Arg.Any<CancellationToken>())
|
||||
.Returns(2);
|
||||
|
||||
//act
|
||||
var updateRangeResult = await service
|
||||
.UpdateRange(commitRequest, dtos, CancellationToken.None);
|
||||
|
||||
updateRangeResult = await service
|
||||
.UpdateRange(commitRequest, dtos, CancellationToken.None);
|
||||
|
||||
updateRangeResult = await service
|
||||
.UpdateRange(commitRequest, dtos, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await changeLogCommitRepository.Received(1).Add(commitRequest, CancellationToken.None);
|
||||
await changeLogRepository.Received(3).UpdateRange(Arg.Any<ChangeLogCommitDto>(), dtos, CancellationToken.None);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MarkAsDeleted()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Uuid7.Guid();
|
||||
var expectedCommitId = Uuid7.Guid();
|
||||
var comment = "Удаление нескольких значений";
|
||||
var commitRequest = new CreateChangeLogCommitRequest(Uuid7.Guid(), comment);
|
||||
var commit = new ChangeLogCommitDto(expectedCommitId, commitRequest);
|
||||
var dtos = GenerateChangeLogValuesDto(2);
|
||||
var dtoIds = dtos.Select(d => d.Id);
|
||||
|
||||
changeLogCommitRepository.Add(Arg.Any<CreateChangeLogCommitRequest>(), Arg.Any<CancellationToken>()).Returns(expectedCommitId);
|
||||
changeLogRepository
|
||||
.MarkAsDeleted(
|
||||
Arg.Any<Guid>(),
|
||||
Arg.Any<IEnumerable<Guid>>(),
|
||||
Arg.Any<DateTimeOffset>(),
|
||||
Arg.Any<CancellationToken>())
|
||||
.Returns(2);
|
||||
|
||||
//act
|
||||
var markAsDeletedResult = await service
|
||||
.MarkAsDeleted(dtoIds, commitRequest, CancellationToken.None);
|
||||
markAsDeletedResult = await service
|
||||
.MarkAsDeleted(dtoIds, commitRequest, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await changeLogCommitRepository.Received(1).Add(commitRequest, CancellationToken.None);
|
||||
await changeLogRepository.Received(2).MarkAsDeleted(commit.Id, dtoIds, Arg.Any<DateTimeOffset>(), CancellationToken.None);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClearAndAddRange()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Uuid7.Guid();
|
||||
var expectedCommitId = Uuid7.Guid();
|
||||
var comment = "Удаление и добавление нескольких значений";
|
||||
var commitRequest = new CreateChangeLogCommitRequest(expectedCommitId, comment);
|
||||
var commit = new ChangeLogCommitDto(expectedCommitId, commitRequest);
|
||||
var dtos = GenerateChangeLogValuesDto(2);
|
||||
var dtoIds = dtos.Select(d => d.Id);
|
||||
|
||||
changeLogCommitRepository.Add(Arg.Any<CreateChangeLogCommitRequest>(), Arg.Any<CancellationToken>()).Returns(Uuid7.Guid());
|
||||
changeLogRepository
|
||||
.ClearAndAddRange(
|
||||
Arg.Any<Guid>(),
|
||||
Arg.Any<ChangeLogCommitDto>(),
|
||||
Arg.Any<IEnumerable<ChangeLogValuesDto>>(),
|
||||
Arg.Any<CancellationToken>())
|
||||
.Returns(2);
|
||||
|
||||
//act
|
||||
var clearAndAddResult = await service
|
||||
.ClearAndAddRange(discriminatorId, commitRequest, dtos, CancellationToken.None);
|
||||
clearAndAddResult = await service
|
||||
.ClearAndAddRange(discriminatorId, commitRequest, dtos, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await changeLogCommitRepository.Received(1).Add(commitRequest, CancellationToken.None);
|
||||
await changeLogRepository.Received(2).ClearAndAddRange(discriminatorId, Arg.Any<ChangeLogCommitDto>(), dtos, CancellationToken.None);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetByDate()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Uuid7.Guid();
|
||||
var paginationRequest = new PaginationRequest()
|
||||
{
|
||||
Skip = 0,
|
||||
Take = 1000
|
||||
};
|
||||
var dtos = GenerateChangeLogValuesDto(5);
|
||||
var items = new PaginationContainer<ChangeLogValuesDto>()
|
||||
{
|
||||
Take = paginationRequest.Take,
|
||||
Skip = paginationRequest.Skip,
|
||||
Items = dtos,
|
||||
Count = 10
|
||||
};
|
||||
var momentDate = DateTime.UtcNow;
|
||||
|
||||
changeLogRepository
|
||||
.GetByDate(
|
||||
Arg.Any<Guid>(),
|
||||
Arg.Any<DateTimeOffset>(),
|
||||
Arg.Any<PaginationRequest>(),
|
||||
Arg.Any<CancellationToken>())
|
||||
.Returns(items);
|
||||
|
||||
//act
|
||||
var actualItems = await service
|
||||
.GetByDate(discriminatorId, momentDate, paginationRequest, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await changeLogRepository.Received(1).GetByDate(discriminatorId, momentDate, paginationRequest, CancellationToken.None);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChangeLogForInterval()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Uuid7.Guid();
|
||||
var dtos = GenerateChangeLogDto(5);
|
||||
|
||||
var dateBegin = DateTimeOffset.UtcNow.AddDays(-5);
|
||||
var dateEnd = DateTimeOffset.UtcNow;
|
||||
|
||||
changeLogRepository
|
||||
.GetChangeLogForInterval(
|
||||
Arg.Any<Guid>(),
|
||||
Arg.Any<DateTimeOffset>(),
|
||||
Arg.Any<DateTimeOffset>(),
|
||||
Arg.Any<CancellationToken>())
|
||||
.Returns(dtos);
|
||||
|
||||
//act
|
||||
var actualItems = await service
|
||||
.GetChangeLogForInterval(discriminatorId, dateBegin, dateEnd, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await changeLogRepository.Received(1).GetChangeLogForInterval(discriminatorId, dateBegin, dateEnd, CancellationToken.None);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDatesChange()
|
||||
{
|
||||
//arrange
|
||||
var discriminatorId = Uuid7.Guid();
|
||||
|
||||
var dateBegin = DateTimeOffset.UtcNow.AddDays(-5);
|
||||
var dateEnd = DateTimeOffset.UtcNow;
|
||||
|
||||
var dateOnlyBegin = new DateOnly(dateBegin.Year, dateBegin.Month, dateBegin.Day);
|
||||
var dateOnlyEnd = new DateOnly(dateEnd.Year, dateEnd.Month, dateEnd.Day);
|
||||
|
||||
var dtos = new List<DateOnly>() { dateOnlyBegin, dateOnlyEnd };
|
||||
|
||||
changeLogRepository
|
||||
.GetDatesChange(
|
||||
Arg.Any<Guid>(),
|
||||
Arg.Any<CancellationToken>())
|
||||
.Returns(dtos);
|
||||
|
||||
//act
|
||||
var actualItems = await service
|
||||
.GetDatesChange(discriminatorId, CancellationToken.None);
|
||||
|
||||
//assert
|
||||
await changeLogRepository.Received(1).GetDatesChange(discriminatorId, CancellationToken.None);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<ChangeLogValuesDto> GenerateChangeLogValuesDto(int count)
|
||||
{
|
||||
var items = new List<ChangeLogValuesDto>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
items.Add(new ChangeLogValuesDto()
|
||||
{
|
||||
|
||||
Id = Uuid7.Guid(),
|
||||
Value = new Dictionary<string, object>
|
||||
{
|
||||
{ "1", 1 },
|
||||
{ "2", 2 }
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private IEnumerable<ChangeLogDto> GenerateChangeLogDto(int count)
|
||||
{
|
||||
var items = new List<ChangeLogDto>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
items.Add(new ChangeLogDto()
|
||||
{
|
||||
Id = Uuid7.Guid(),
|
||||
});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DD.Persistence.API\DD.Persistence.API.csproj" />
|
||||
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -14,9 +14,10 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi<ChangeLogValuesDto>
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<IActionResult> ClearAndAddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение данных на текущую дату (с пагинацией)
|
||||
@ -47,55 +48,33 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi<ChangeLogValuesDto>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить одну запись
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавить несколько записей
|
||||
/// </summary>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment">комментарий</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить одну запись
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> Update(ChangeLogValuesDto dto, CancellationToken token);
|
||||
Task<IActionResult> AddRange(Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить несколько записей
|
||||
/// </summary>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="comment">комментарий</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить одну запись
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> Delete(Guid id, CancellationToken token);
|
||||
Task<IActionResult> UpdateRange(IEnumerable<ChangeLogValuesDto> dtos, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить несколько записей
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="comment">комментарий к удалению</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IActionResult> DeleteRange(IEnumerable<Guid> ids, CancellationToken token);
|
||||
Task<IActionResult> DeleteRange(IEnumerable<Guid> ids, string comment, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
|
||||
|
22
DD.Persistence/Repositories/IChangeLogCommitRepository.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using DD.Persistence.Models.Requests;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DD.Persistence.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс для работы с коммитами журнала изменений
|
||||
/// </summary>
|
||||
public interface IChangeLogCommitRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Добавить коммит для журнала изменений
|
||||
/// </summary>
|
||||
/// <param name="commitDto"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<Guid> Add(CreateChangeLogCommitRequest commitDto, CancellationToken token);
|
||||
}
|
@ -1,61 +1,63 @@
|
||||
using DD.Persistence.Models;
|
||||
using DD.Persistence.Models.Common;
|
||||
using DD.Persistence.Models.Requests;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
|
||||
|
||||
namespace DD.Persistence.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс для работы с историческими данными
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto"></typeparam>
|
||||
public interface IChangeLogRepository : ISyncWithDiscriminatorRepository<ChangeLogValuesDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Добавление записей
|
||||
/// </summary>
|
||||
/// <param name="idAuthor">пользователь, который добавляет</param>
|
||||
/// <param name="idDiscriminator">ключ справочника</param>
|
||||
/// <param name="dto">коммит с изменениями</param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> AddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<int> AddRange(Guid idDiscriminator, ChangeLogCommitDto dto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Пометить записи как удаленные
|
||||
/// </summary>
|
||||
/// <param name="idEditor"></param>
|
||||
/// <param name="idCommit"></param>
|
||||
/// <param name="ids">ключи записей</param>
|
||||
/// <param name="updateTime"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> MarkAsDeleted(Guid idEditor, IEnumerable<Guid> ids, CancellationToken token);
|
||||
Task<int> MarkAsDeleted(Guid idCommit, IEnumerable<Guid> ids, DateTimeOffset updateTime, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Пометить записи как удаленные
|
||||
/// </summary>
|
||||
/// <param name="idEditor"></param>
|
||||
/// <param name="idDiscriminator">дискриминатор таблицы</param>
|
||||
/// <param name="idCommit"></param>
|
||||
/// <param name="updateTime"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> MarkAsDeleted(Guid idEditor, Guid idDiscriminator, CancellationToken token);
|
||||
Task<int> MarkAsDeleted(Guid idDiscriminator, Guid idCommit, DateTimeOffset updateTime, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Очистить и добавить новые
|
||||
/// </summary>
|
||||
/// <param name="idAuthor"></param>
|
||||
/// <param name="idDiscriminator"></param>
|
||||
/// <param name="dto">коммит с изменениями</param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> ClearAndAddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<int> ClearAndAddRange(Guid idDiscriminator, ChangeLogCommitDto dto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Редактирование записей
|
||||
/// </summary>
|
||||
/// <param name="idEditor">пользователь, который редактирует</param>
|
||||
/// <param name="commitDto">коммит с изменениями</param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> UpdateRange(Guid idEditor, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
Task<int> UpdateRange(ChangeLogCommitDto commitDto, IEnumerable<ChangeLogValuesDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение актуальных записей на определенный момент времени (с пагинацией)
|
||||
|
Не ошибка, но почему не private readonly поле как везде? +Свойства == синтаксический сахар для методов Get_..() Set_..(), А значит они должны называться с большой буквы.