diff --git a/DD.Persistence.API/Controllers/ChangeLogController.cs b/DD.Persistence.API/Controllers/ChangeLogController.cs
index f10ae1a..138572d 100644
--- a/DD.Persistence.API/Controllers/ChangeLogController.cs
+++ b/DD.Persistence.API/Controllers/ChangeLogController.cs
@@ -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;
-
+///
+/// Контроллер по работе с журналом изменений
+///
[ApiController]
[Authorize]
[Route("api/[controller]")]
public class ChangeLogController : ControllerBase, IChangeLogApi
{
- private readonly IChangeLogRepository repository;
+ private ChangeLogService service { get; }
- public ChangeLogController(IChangeLogRepository repository)
+ ///
+ /// ctor
+ ///
+ ///
+ public ChangeLogController(ChangeLogService service)
{
- this.repository = repository;
+ this.service = service;
}
+ ///
+ /// Добавить записи в журнал изменений по дискриминатору
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[HttpPost("{idDiscriminator}")]
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
- public async Task Add(
- [FromRoute] Guid idDiscriminator,
- [FromBody] ChangeLogValuesDto dto,
- CancellationToken token)
- {
- var userId = User.GetUserId();
- 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 AddRange(
[FromRoute] Guid idDiscriminator,
[FromBody] IEnumerable dtos,
+ string comment,
CancellationToken token)
{
var userId = User.GetUserId();
- 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);
}
+ ///
+ /// Удалить записи в журнале изменений
+ ///
+ ///
+ ///
+ ///
+ ///
[HttpDelete]
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
- public async Task Delete(Guid id, CancellationToken token)
+ public async Task DeleteRange(IEnumerable ids, string comment, CancellationToken token)
{
var userId = User.GetUserId();
- 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 DeleteRange(IEnumerable ids, CancellationToken token)
- {
- var userId = User.GetUserId();
- var result = await repository.MarkAsDeleted(userId, ids, token);
-
- return Ok(result);
- }
+ ///
+ /// Очистить все записи в журнале изменений (по дискриминатору) и добавить новые
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[HttpPost("replace/{idDiscriminator}")]
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
public async Task ClearAndAddRange(
[FromRoute] Guid idDiscriminator,
[FromBody] IEnumerable dtos,
+ string comment,
CancellationToken token)
{
var userId = User.GetUserId();
- 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);
}
+ ///
+ /// сохранить изменения в записях журнала изменений
+ ///
+ ///
+ ///
+ ///
+ ///
[HttpPut]
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
- public async Task Update(
- ChangeLogValuesDto dto,
- CancellationToken token)
- {
- var userId = User.GetUserId();
- var result = await repository.UpdateRange(userId, [dto], token);
-
- return Ok(result);
- }
-
- [HttpPut("range")]
- [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
public async Task UpdateRange(
IEnumerable dtos,
+ string comment,
CancellationToken token)
{
var userId = User.GetUserId();
- 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);
}
+ ///
+ /// Получение актуальных записей (с пагинацией)
+ ///
+ ///
+ ///
+ ///
+ ///
[HttpGet("{idDiscriminator}")]
[ProducesResponseType(typeof(PaginationContainer), (int)HttpStatusCode.OK)]
public async Task 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);
}
+ ///
+ /// Получение записей на определенный момент времени (с пагинацией)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[HttpGet("moment/{idDiscriminator}")]
[ProducesResponseType(typeof(PaginationContainer), (int)HttpStatusCode.OK)]
public async Task 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);
}
+ ///
+ /// Получение измененных записей за период времени
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[HttpGet("history/{idDiscriminator}")]
[ProducesResponseType(typeof(IEnumerable), (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);
}
+ ///
+ /// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
+ ///
+ ///
+ ///
+ ///
[HttpGet("datesChange/{idDiscriminator}")]
[ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
public async Task GetDatesChange([FromRoute] Guid idDiscriminator, CancellationToken token)
{
- var result = await repository.GetDatesChange(idDiscriminator, token);
+ var result = await service.GetDatesChange(idDiscriminator, token);
return Ok(result);
}
+ ///
+ /// Получение данных, начиная с определенной даты
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[HttpGet("part/{idDiscriminator}")]
[ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
public async Task>> 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);
}
+ ///
+ /// Получить диапазон дат, для которых есть данные в репозитории
+ ///
+ ///
+ ///
+ ///
[HttpGet("datesRange/{idDiscriminator}")]
[ProducesResponseType(typeof(DatesRangeDto), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
public async Task> 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();
@@ -232,7 +285,7 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
IdEditor = userId,
IdNext = changeLogItemCurrentId,
Obsolete = DateTimeOffset.UtcNow.AddDays(-5),
- Value = new ChangeLogValuesDto(){
+ Value = new ChangeLogValuesDto(){
Id = Guid.CreateVersion7(),
Value = new Dictionary() {
["1"] = new { id = 1, caption = "Изменение 1" },
@@ -242,7 +295,7 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
}
};
var result = new List() {
- new() {
+ new() {
Comment = "Петров И. Ю. попросил внести изменения",
DateTime = changeLogItemCreation,
DiscriminatorId = Guid.CreateVersion7(),
diff --git a/DD.Persistence.API/DependencyInjection.cs b/DD.Persistence.API/DependencyInjection.cs
index 30d9f89..6052a51 100644
--- a/DD.Persistence.API/DependencyInjection.cs
+++ b/DD.Persistence.API/DependencyInjection.cs
@@ -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();
services.AddTransient();
+ services.AddTransient();
}
#region Authentication
diff --git a/DD.Persistence.API/Services/ChangeLogService.cs b/DD.Persistence.API/Services/ChangeLogService.cs
new file mode 100644
index 0000000..f4831d2
--- /dev/null
+++ b/DD.Persistence.API/Services/ChangeLogService.cs
@@ -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;
+
+///
+/// Сервис по работе с журналом изменений
+///
+public class ChangeLogService
+{
+ private readonly IMemoryCache memoryCache;
+ private readonly IChangeLogCommitRepository commitRepository;
+ private readonly IChangeLogRepository repository;
+ private readonly TimeSpan? AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60);
+
+ ///
+ /// ctor
+ ///
+ ///
+ ///
+ ///
+ public ChangeLogService(
+ IMemoryCache memoryCache,
+ IChangeLogCommitRepository commitRepository,
+ IChangeLogRepository repository)
+ {
+ this.memoryCache = memoryCache;
+ this.commitRepository = commitRepository;
+ this.repository = repository;
+ }
+
+ ///
+ /// Чтение ключа коммита из кеша или (если коммита в кеше нет) создание коммита
+ ///
+ ///
+ ///
+ ///
+ private async Task GetOrCreateCommitAsync(CreateChangeLogCommitRequest commitDto, CancellationToken token)
+ {
+ 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;
+ }
+
+ ///
+ /// Добавление записи в журнал изменений
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task AddRange(Guid idDiscriminator, CreateChangeLogCommitRequest commitRequestDto, IEnumerable 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;
+ }
+
+ ///
+ /// Пометить запись журнала изменений как удаленную
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task MarkAsDeleted(IEnumerable 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;
+ }
+
+ ///
+ /// Очистить старые и добавить новые записи в журнал изменений
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task ClearAndAddRange(Guid idDiscriminator, CreateChangeLogCommitRequest commitRequestDto, IEnumerable 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;
+ }
+
+ ///
+ /// Обновить записи в журнале изменений
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task UpdateRange(CreateChangeLogCommitRequest commitRequestDto, IEnumerable 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;
+ }
+
+ ///
+ /// Получение актуальных записей на определенный момент времени (с пагинацией)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetByDate(
+ Guid idDiscriminator,
+ DateTimeOffset momentUtc,
+ PaginationRequest paginationRequest,
+ CancellationToken token)
+ {
+ var result = await repository.GetByDate(idDiscriminator, momentUtc, paginationRequest, token);
+
+ return result;
+ }
+
+ ///
+ /// Получение измененных записей за период времени
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
+ {
+ var result = await repository.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, token);
+
+ return result;
+ }
+
+ ///
+ /// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetDatesChange(Guid idDiscriminator, CancellationToken token)
+ {
+ var result = await repository.GetDatesChange(idDiscriminator, token);
+
+ return result;
+ }
+
+ ///
+ /// Получить данные, начиная с определенной даты
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetGtDate(Guid idDiscriminator, DateTimeOffset dateBegin, CancellationToken token)
+ {
+ var result = await repository.GetGtDate(idDiscriminator, dateBegin, token);
+
+ return result;
+ }
+
+ ///
+ /// Получить диапазон дат, для которых есть данные в репозитории
+ ///
+ ///
+ ///
+ ///
+ public async Task GetDatesRange(Guid idDiscriminator, CancellationToken token)
+ {
+ var result = await repository.GetDatesRange(idDiscriminator, token);
+
+ return result;
+ }
+}
diff --git a/DD.Persistence.Client/Clients/ChangeLogClient.cs b/DD.Persistence.Client/Clients/ChangeLogClient.cs
index fa73ba9..ab023c7 100644
--- a/DD.Persistence.Client/Clients/ChangeLogClient.cs
+++ b/DD.Persistence.Client/Clients/ChangeLogClient.cs
@@ -19,10 +19,10 @@ public class ChangeLogClient : BaseClient, IChangeLogClient
}
///
- public async Task ClearAndAddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token)
+ public async Task ClearAndAddRange(Guid idDiscriminator, IEnumerable 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
}
///
- public async Task Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token)
+ public async Task AddRange(Guid idDiscriminator, IEnumerable 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;
}
///
- public async Task AddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token)
+ public async Task UpdateRange(IEnumerable 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;
}
///
- public async Task Update(ChangeLogValuesDto dto, CancellationToken token)
+ public async Task DeleteRange(IEnumerable ids, string comment, CancellationToken token)
{
var result = await ExecutePostResponse(
- async () => await refitChangeLogClient.Update(dto, token), token);
-
- return result;
- }
-
- ///
- public async Task UpdateRange(IEnumerable dtos, CancellationToken token)
- {
- var result = await ExecutePostResponse(
- async () => await refitChangeLogClient.UpdateRange(dtos, token), token);
-
- return result;
- }
-
- ///
- public async Task Delete(Guid id, CancellationToken token)
- {
- var result = await ExecutePostResponse(
- async () => await refitChangeLogClient.Delete(id, token), token);
-
- return result;
- }
-
- ///
- public async Task DeleteRange(IEnumerable ids, CancellationToken token)
- {
- var result = await ExecutePostResponse(
- async () => await refitChangeLogClient.DeleteRange(ids, token), token);
+ async () => await refitChangeLogClient.DeleteRange(ids, comment, token), token);
return result;
}
diff --git a/DD.Persistence.Client/Clients/Interfaces/IChangeLogClient.cs b/DD.Persistence.Client/Clients/Interfaces/IChangeLogClient.cs
index 16a491c..824d247 100644
--- a/DD.Persistence.Client/Clients/Interfaces/IChangeLogClient.cs
+++ b/DD.Persistence.Client/Clients/Interfaces/IChangeLogClient.cs
@@ -9,48 +9,34 @@ namespace DD.Persistence.Client.Clients.Interfaces;
///
public interface IChangeLogClient : IDisposable
{
- ///
- /// Добавить одну запись
- ///
- ///
- ///
- ///
- ///
- Task Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
+ ///
+ /// Добавить несколько записей
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task AddRange(Guid idDiscriminator, IEnumerable dtos, string comment, CancellationToken token);
- ///
- /// Добавить несколько записей
- ///
- ///
- ///
- ///
- ///
- Task AddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token);
+ ///
+ /// Импорт с заменой: удаление старых строк и добавление новых
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task ClearAndAddRange(Guid idDiscriminator, IEnumerable dtos, string comment, CancellationToken token);
- ///
- /// Импорт с заменой: удаление старых строк и добавление новых
- ///
- ///
- ///
- ///
- ///
- Task ClearAndAddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token);
-
- ///
- /// Удалить одну запись
- ///
- ///
- ///
- ///
- Task Delete(Guid id, CancellationToken token);
-
- ///
- /// Удалить несколько записей
- ///
- ///
- ///
- ///
- Task DeleteRange(IEnumerable ids, CancellationToken token);
+ ///
+ /// Удалить несколько записей
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task DeleteRange(IEnumerable ids, string comment, CancellationToken token);
///
/// Получение актуальных данных на определенную дату (с пагинацией)
@@ -80,19 +66,12 @@ public interface IChangeLogClient : IDisposable
///
Task GetDatesRange(Guid idDiscriminator, CancellationToken token);
- ///
- /// Обновить одну запись
- ///
- ///
- ///
- ///
- Task Update(ChangeLogValuesDto dto, CancellationToken token);
-
- ///
- /// Обновить несколько записей
- ///
- ///
- ///
- ///
- Task UpdateRange(IEnumerable dtos, CancellationToken token);
+ ///
+ /// Обновить несколько записей
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task UpdateRange(IEnumerable dtos, string comment, CancellationToken token);
}
\ No newline at end of file
diff --git a/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitChangeLogClient.cs b/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitChangeLogClient.cs
index a07fac3..6d0425b 100644
--- a/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitChangeLogClient.cs
+++ b/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitChangeLogClient.cs
@@ -16,7 +16,7 @@ public interface IRefitChangeLogClient : IRefitClient, IDisposable
/// Импорт с заменой: удаление старых строк и добавление новых
///
[Post($"{BaseRoute}/replace/{{idDiscriminator}}")]
- Task> ClearAndAddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token);
+ Task> ClearAndAddRange(Guid idDiscriminator, IEnumerable dtos, string comment, CancellationToken token);
///
/// Получение актуальных данных на определенную дату (с пагинацией)
@@ -34,41 +34,23 @@ public interface IRefitChangeLogClient : IRefitClient, IDisposable
[Get($"{BaseRoute}/history/{{idDiscriminator}}")]
Task>> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
- ///
- /// Добавить одну запись
- ///
- [Post($"{BaseRoute}/{{idDiscriminator}}")]
- Task> Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
-
///
/// Добавить несколько записей
///
- [Post($"{BaseRoute}/range/{{idDiscriminator}}")]
- Task> AddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token);
-
- ///
- /// Обновить одну запись
- ///
- [Put($"{BaseRoute}")]
- Task> Update(ChangeLogValuesDto dto, CancellationToken token);
+ [Post($"{BaseRoute}/{{idDiscriminator}}")]
+ Task> AddRange(Guid idDiscriminator, IEnumerable dtos, string comment, CancellationToken token);
///
/// Обновить несколько записей
///
- [Put($"{BaseRoute}/range")]
- Task> UpdateRange(IEnumerable dtos, CancellationToken token);
-
- ///
- /// Удалить одну запись
- ///
- [Delete($"{BaseRoute}")]
- Task> Delete(Guid id, CancellationToken token);
+ [Put($"{BaseRoute}")]
+ Task> UpdateRange(IEnumerable dtos, string comment, CancellationToken token);
///
/// Удалить несколько записей
///
- [Delete($"{BaseRoute}/range")]
- Task> DeleteRange([Body] IEnumerable ids, CancellationToken token);
+ [Delete($"{BaseRoute}")]
+ Task> DeleteRange([Body] IEnumerable ids, string comment, CancellationToken token);
///
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
diff --git a/DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.Designer.cs b/DD.Persistence.Database.Postgres/Migrations/20250221053248_Init.Designer.cs
similarity index 78%
rename from DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.Designer.cs
rename to DD.Persistence.Database.Postgres/Migrations/20250221053248_Init.Designer.cs
index 5cd7da2..e541b06 100644
--- a/DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.Designer.cs
+++ b/DD.Persistence.Database.Postgres/Migrations/20250221053248_Init.Designer.cs
@@ -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
{
///
@@ -41,18 +41,18 @@ namespace DD.Persistence.Database.Postgres.Migrations
.HasColumnType("uuid")
.HasComment("Дискриминатор таблицы");
- b.Property("IdAuthor")
+ b.Property("IdCreatedCommit")
.HasColumnType("uuid")
- .HasComment("Автор изменения");
-
- b.Property("IdEditor")
- .HasColumnType("uuid")
- .HasComment("Редактор");
+ .HasComment("Id коммита на создание записи");
b.Property("IdNext")
.HasColumnType("uuid")
.HasComment("Id заменяющей записи");
+ b.Property("IdObsoletedCommit")
+ .HasColumnType("uuid")
+ .HasComment("Id коммита на устаревание записи");
+
b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasComment("Id коммита");
+
+ b.Property("Comment")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasComment("Комментарий к коммиту");
+
+ b.Property("Creation")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("Дата создания коммита");
+
+ b.Property("IdAuthor")
+ .HasColumnType("uuid")
+ .HasComment("Пользователь, создавший коммит");
+
+ b.HasKey("Id");
+
+ b.ToTable("change_log_commit");
+ });
+
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
{
b.Property("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
}
}
diff --git a/DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.cs b/DD.Persistence.Database.Postgres/Migrations/20250221053248_Init.cs
similarity index 78%
rename from DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.cs
rename to DD.Persistence.Database.Postgres/Migrations/20250221053248_Init.cs
index a1dd229..728fc4b 100644
--- a/DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.cs
+++ b/DD.Persistence.Database.Postgres/Migrations/20250221053248_Init.cs
@@ -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(type: "uuid", nullable: false, comment: "Ключ записи"),
- DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"),
- IdAuthor = table.Column(type: "uuid", nullable: false, comment: "Автор изменения"),
- IdEditor = table.Column(type: "uuid", nullable: true, comment: "Редактор"),
- Creation = table.Column(type: "timestamp with time zone", nullable: false, comment: "Дата создания записи"),
- Obsolete = table.Column(type: "timestamp with time zone", nullable: true, comment: "Дата устаревания (например при удалении)"),
- IdNext = table.Column(type: "uuid", nullable: true, comment: "Id заменяющей записи"),
- Value = table.Column(type: "jsonb", nullable: false, comment: "Значение")
+ Id = table.Column(type: "uuid", nullable: false, comment: "Id коммита"),
+ IdAuthor = table.Column(type: "uuid", nullable: false, comment: "Пользователь, создавший коммит"),
+ Creation = table.Column(type: "timestamp with time zone", nullable: false, comment: "Дата создания коммита"),
+ Comment = table.Column(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(type: "uuid", nullable: false, comment: "Ключ записи"),
+ DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"),
+ Creation = table.Column(type: "timestamp with time zone", nullable: false, comment: "Дата создания записи"),
+ Obsolete = table.Column(type: "timestamp with time zone", nullable: true, comment: "Дата устаревания (например при удалении)"),
+ IdNext = table.Column(type: "uuid", nullable: true, comment: "Id заменяющей записи"),
+ Value = table.Column(type: "jsonb", nullable: false, comment: "Значение"),
+ IdCreatedCommit = table.Column(type: "uuid", nullable: false, comment: "Id коммита на создание записи"),
+ IdObsoletedCommit = table.Column(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");
}
diff --git a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs
index 59361b8..274d157 100644
--- a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs
+++ b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs
@@ -38,18 +38,18 @@ namespace DD.Persistence.Database.Postgres.Migrations
.HasColumnType("uuid")
.HasComment("Дискриминатор таблицы");
- b.Property("IdAuthor")
+ b.Property("IdCreatedCommit")
.HasColumnType("uuid")
- .HasComment("Автор изменения");
-
- b.Property("IdEditor")
- .HasColumnType("uuid")
- .HasComment("Редактор");
+ .HasComment("Id коммита на создание записи");
b.Property("IdNext")
.HasColumnType("uuid")
.HasComment("Id заменяющей записи");
+ b.Property("IdObsoletedCommit")
+ .HasColumnType("uuid")
+ .HasComment("Id коммита на устаревание записи");
+
b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasComment("Id коммита");
+
+ b.Property("Comment")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasComment("Комментарий к коммиту");
+
+ b.Property("Creation")
+ .HasColumnType("timestamp with time zone")
+ .HasComment("Дата создания коммита");
+
+ b.Property("IdAuthor")
+ .HasColumnType("uuid")
+ .HasComment("Пользователь, создавший коммит");
+
+ b.HasKey("Id");
+
+ b.ToTable("change_log_commit");
+ });
+
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
{
b.Property("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
}
}
diff --git a/DD.Persistence.Database/DependencyInjection.cs b/DD.Persistence.Database/DependencyInjection.cs
index 91b6956..268edd9 100644
--- a/DD.Persistence.Database/DependencyInjection.cs
+++ b/DD.Persistence.Database/DependencyInjection.cs
@@ -45,6 +45,7 @@ public static class DependencyInjection
//services.AddTransient(typeof(PersistenceRepository));
services.AddTransient();
+ services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
diff --git a/DD.Persistence.Database/Entity/ChangeLog.cs b/DD.Persistence.Database/Entity/ChangeLog.cs
index a0047cb..3621795 100644
--- a/DD.Persistence.Database/Entity/ChangeLog.cs
+++ b/DD.Persistence.Database/Entity/ChangeLog.cs
@@ -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; }
@@ -36,4 +30,16 @@ public class ChangeLog : IDiscriminatorItem, IChangeLog
[Column(TypeName = "jsonb"), Comment("Значение")]
public required IDictionary Value { get; set; }
+
+ [Required, Comment("Id коммита на создание записи")]
+ public Guid IdCreatedCommit { get; set; }
+
+ [Comment("Id коммита на устаревание записи")]
+ public Guid? IdObsoletedCommit { get; set; }
+
+ [Required, ForeignKey(nameof(IdCreatedCommit)), Comment("Коммит пользователя на создание записи")]
+ public virtual ChangeLogCommit CreatedCommit { get; set; } = null!;
+
+ [ForeignKey(nameof(IdObsoletedCommit)), Comment("Коммит пользователя на устаревание записи")]
+ public virtual ChangeLogCommit? ObsoletedCommit { get; set; }
}
diff --git a/DD.Persistence.Database/Entity/ChangeLogCommit.cs b/DD.Persistence.Database/Entity/ChangeLogCommit.cs
new file mode 100644
index 0000000..8e17df0
--- /dev/null
+++ b/DD.Persistence.Database/Entity/ChangeLogCommit.cs
@@ -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;
+
+///
+/// Таблица c коммитами пользователей
+///
+[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 ChangeLogCreatedItems { get; set; } = null!;
+
+ [InverseProperty(nameof(ChangeLog.ObsoletedCommit)), Comment("Устаревшие записи в журнале изменений")]
+ public virtual ICollection? ChangeLogObsoletedItems { get; set; } = null!;
+}
diff --git a/DD.Persistence.Database/EntityAbstractions/IChangeLog.cs b/DD.Persistence.Database/EntityAbstractions/IChangeLog.cs
index fb8219c..bb5e68a 100644
--- a/DD.Persistence.Database/EntityAbstractions/IChangeLog.cs
+++ b/DD.Persistence.Database/EntityAbstractions/IChangeLog.cs
@@ -10,16 +10,6 @@ public interface IChangeLog
///
public Guid Id { get; set; }
- ///
- /// Автор изменения
- ///
- public Guid IdAuthor { get; set; }
-
- ///
- /// Редактор
- ///
- public Guid? IdEditor { get; set; }
-
///
/// Дата создания записи
///
diff --git a/DD.Persistence.Database/PersistenceDbContext.cs b/DD.Persistence.Database/PersistenceDbContext.cs
index 4b0a874..1337b21 100644
--- a/DD.Persistence.Database/PersistenceDbContext.cs
+++ b/DD.Persistence.Database/PersistenceDbContext.cs
@@ -16,6 +16,8 @@ public class PersistenceDbContext : DbContext
public DbSet ChangeLog => Set();
+ public DbSet ChangeLogCommit => Set();
+
public DbSet TechMessage => Set();
public DbSet ParameterData => Set();
diff --git a/DD.Persistence.Database/Repositories/ChangeLogCommitRepository.cs b/DD.Persistence.Database/Repositories/ChangeLogCommitRepository.cs
new file mode 100644
index 0000000..634136c
--- /dev/null
+++ b/DD.Persistence.Database/Repositories/ChangeLogCommitRepository.cs
@@ -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 Add(CreateChangeLogCommitRequest commitRequestDto, CancellationToken token)
+ {
+
+ 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;
+ }
+}
diff --git a/DD.Persistence.Database/Repositories/ChangeLogRepository.cs b/DD.Persistence.Database/Repositories/ChangeLogRepository.cs
index 488f9ef..18aa5fb 100644
--- a/DD.Persistence.Database/Repositories/ChangeLogRepository.cs
+++ b/DD.Persistence.Database/Repositories/ChangeLogRepository.cs
@@ -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 AddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable dtos, CancellationToken token)
+ public async Task AddRange(Guid idDiscriminator, ChangeLogCommitDto commitDto, IEnumerable dtos, CancellationToken token)
{
var entities = new List();
- 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().AddRange(entities);
@@ -33,7 +42,7 @@ public class ChangeLogRepository : IChangeLogRepository
return result;
}
- public async Task MarkAsDeleted(Guid idEditor, IEnumerable ids, CancellationToken token)
+ public async Task MarkAsDeleted(Guid idCommit, IEnumerable ids, DateTimeOffset updateTime, CancellationToken token)
{
var query = db.Set()
.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);
+ foreach (var entity in entities)
+ {
+ entity.Obsolete = updateTime;
+ entity.IdObsoletedCommit = idCommit;
+ }
- return result;
+ return await db.SaveChangesAsync(token);
}
- public async Task MarkAsDeleted(Guid idEditor, Guid idDiscriminator, CancellationToken token)
+ public async Task MarkAsDeleted(Guid idDiscriminator, Guid idCommit, DateTimeOffset updateTime, CancellationToken token)
{
var query = db.Set()
.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 MarkAsObsolete(Guid idEditor, IEnumerable 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 ClearAndAddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable dtos, CancellationToken token)
+
+ public async Task ClearAndAddRange(Guid idDiscriminator, ChangeLogCommitDto commitDto, IEnumerable dtos, CancellationToken token)
{
var result = 0;
+ var changeLogIds = dtos.Select(c => c.Id);
+ var comment = commitDto.Comment;
+
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);
+ result += await AddRange(idDiscriminator, commitDto, dtos, token);
await transaction.CommitAsync(token);
-
return result;
}
- public async Task UpdateRange(Guid idEditor, IEnumerable dtos, CancellationToken token)
+ public async Task UpdateRange(ChangeLogCommitDto commitDto, IEnumerable dtos, CancellationToken token)
{
var dbSet = db.Set();
@@ -101,7 +108,6 @@ public class ChangeLogRepository : IChangeLogRepository
.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)
@@ -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> 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> GetGtDate(Guid idDiscriminator, DateTimeOffset dateBegin, CancellationToken token)
{
var date = dateBegin.ToUniversalTime();
diff --git a/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs
index 7a56e5f..b17641d 100644
--- a/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs
+++ b/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs
@@ -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();
- }
- [Fact]
- public async Task ClearAndInsertRange_InEmptyDb()
- {
- // arrange
- dbContext.CleanupDbSet();
-
- var idDiscriminator = Guid.NewGuid();
- var dtos = Generate(2);
-
- // act
- var result = await client.ClearAndAddRange(idDiscriminator, dtos, new CancellationToken());
-
- // assert
- Assert.Equal(2, result);
+ paginationRequest = new PaginationRequest()
+ {
+ 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());
+ 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());
+ //act
+ 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);
@@ -93,13 +70,14 @@ public class ChangeLogControllerTest : BaseIntegrationTest
[Fact]
public async Task Update_returns_success()
{
- // arrange
+ //arrange
dbContext.CleanupDbSet();
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();
// 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()).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();
- 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()).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));
+ //arrange
+ 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()).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)> 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());
+
+ // 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)> 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();
+ 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);
}
diff --git a/DD.Persistence.Models/ChangeLogCommitDto.cs b/DD.Persistence.Models/ChangeLogCommitDto.cs
new file mode 100644
index 0000000..0df8baf
--- /dev/null
+++ b/DD.Persistence.Models/ChangeLogCommitDto.cs
@@ -0,0 +1,21 @@
+namespace DD.Persistence.Models.Requests;
+
+///
+/// Модель коммита с изменениями
+///
+public class ChangeLogCommitDto : CreateChangeLogCommitRequest
+{
+ ///
+ /// Id
+ ///
+ public Guid Id { get; set; }
+
+ ///
+ ///
+ ///
+ public ChangeLogCommitDto(Guid id, CreateChangeLogCommitRequest request) : base(request.IdAuthor, request.Comment)
+ {
+ Id = id;
+ }
+
+}
diff --git a/DD.Persistence.Models/Requests/CreateChangeLogCommitRequest.cs b/DD.Persistence.Models/Requests/CreateChangeLogCommitRequest.cs
new file mode 100644
index 0000000..e0bcffa
--- /dev/null
+++ b/DD.Persistence.Models/Requests/CreateChangeLogCommitRequest.cs
@@ -0,0 +1,33 @@
+namespace DD.Persistence.Models.Requests;
+
+///
+/// Модель для создания коммита
+///
+public class CreateChangeLogCommitRequest
+{
+ ///
+ /// Дата создания
+ ///
+ public DateTimeOffset Creation { get; set; }
+
+ ///
+ /// Пользователь, совершающий коммит
+ ///
+ public Guid IdAuthor { get; set; }
+
+ ///
+ /// Комментарий
+ ///
+ public string Comment { get; set; } = string.Empty;
+
+ ///
+ ///
+ ///
+ public CreateChangeLogCommitRequest(Guid idAuthor, string comment)
+ {
+ IdAuthor = idAuthor;
+ Comment = comment;
+ Creation = DateTimeOffset.UtcNow;
+ }
+
+}
diff --git a/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj b/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj
index 63b4134..392ac8d 100644
--- a/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj
+++ b/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj
@@ -11,8 +11,8 @@
-
-
+
+
diff --git a/DD.Persistence.Test/ChangeLogTest.cs b/DD.Persistence.Test/ChangeLogTest.cs
new file mode 100644
index 0000000..106dca5
--- /dev/null
+++ b/DD.Persistence.Test/ChangeLogTest.cs
@@ -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();
+ private readonly IChangeLogRepository changeLogRepository = Substitute.For();
+ private ChangeLogService service;
+
+ public ChangeLogTest()
+ {
+ var memoryCache = new MemoryCache(new MemoryCacheOptions());
+ service = new ChangeLogService(memoryCache, changeLogCommitRepository, changeLogRepository);
+ }
+ [Fact]
+ public async Task AddRange()
+ {
+ //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(), Arg.Any()).Returns(Uuid7.Guid());
+ changeLogRepository
+ .AddRange(
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any>(),
+ Arg.Any())
+ .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(), 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(), Arg.Any()).Returns(commit.Id);
+
+ changeLogRepository
+ .UpdateRange(
+ Arg.Any(),
+ Arg.Any>(),
+ Arg.Any())
+ .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(), 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(), Arg.Any()).Returns(expectedCommitId);
+ changeLogRepository
+ .MarkAsDeleted(
+ Arg.Any(),
+ Arg.Any>(),
+ Arg.Any(),
+ Arg.Any())
+ .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(), 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(), Arg.Any()).Returns(Uuid7.Guid());
+ changeLogRepository
+ .ClearAndAddRange(
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any>(),
+ Arg.Any())
+ .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(), 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()
+ {
+ Take = paginationRequest.Take,
+ Skip = paginationRequest.Skip,
+ Items = dtos,
+ Count = 10
+ };
+ var momentDate = DateTime.UtcNow;
+
+ changeLogRepository
+ .GetByDate(
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any())
+ .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(),
+ Arg.Any(),
+ Arg.Any(),
+ Arg.Any())
+ .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() { dateOnlyBegin, dateOnlyEnd };
+
+ changeLogRepository
+ .GetDatesChange(
+ Arg.Any(),
+ Arg.Any())
+ .Returns(dtos);
+
+ //act
+ var actualItems = await service
+ .GetDatesChange(discriminatorId, CancellationToken.None);
+
+ //assert
+ await changeLogRepository.Received(1).GetDatesChange(discriminatorId, CancellationToken.None);
+
+ }
+
+
+ private IEnumerable GenerateChangeLogValuesDto(int count)
+ {
+ var items = new List();
+ for (int i = 0; i < count; i++)
+ {
+ items.Add(new ChangeLogValuesDto()
+ {
+
+ Id = Uuid7.Guid(),
+ Value = new Dictionary
+ {
+ { "1", 1 },
+ { "2", 2 }
+ }
+
+ });
+ }
+ return items;
+ }
+
+ private IEnumerable GenerateChangeLogDto(int count)
+ {
+ var items = new List();
+ for (int i = 0; i < count; i++)
+ {
+ items.Add(new ChangeLogDto()
+ {
+ Id = Uuid7.Guid(),
+ });
+ }
+ return items;
+ }
+}
diff --git a/DD.Persistence.Test/DD.Persistence.Test.csproj b/DD.Persistence.Test/DD.Persistence.Test.csproj
index f71b186..07e0780 100644
--- a/DD.Persistence.Test/DD.Persistence.Test.csproj
+++ b/DD.Persistence.Test/DD.Persistence.Test.csproj
@@ -16,6 +16,7 @@
+
diff --git a/DD.Persistence/API/IChangeLogApi.cs b/DD.Persistence/API/IChangeLogApi.cs
index 5389ba2..0c69d4f 100644
--- a/DD.Persistence/API/IChangeLogApi.cs
+++ b/DD.Persistence/API/IChangeLogApi.cs
@@ -14,9 +14,10 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi
///
///
///
+ ///
///
///
- Task ClearAndAddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token);
+ Task ClearAndAddRange(Guid idDiscriminator, IEnumerable dtos, string comment, CancellationToken token);
///
/// Получение данных на текущую дату (с пагинацией)
@@ -47,55 +48,33 @@ public interface IChangeLogApi : ISyncWithDiscriminatorApi
///
Task GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
- ///
- /// Добавить одну запись
- ///
- ///
- ///
- ///
- ///
- Task Add(Guid idDiscriminator, ChangeLogValuesDto dto, CancellationToken token);
-
///
/// Добавить несколько записей
///
///
///
+ /// комментарий
///
///
- Task AddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token);
-
- ///
- /// Обновить одну запись
- ///
- ///
- ///
- ///
- Task Update(ChangeLogValuesDto dto, CancellationToken token);
+ Task AddRange(Guid idDiscriminator, IEnumerable dtos, string comment, CancellationToken token);
///
/// Обновить несколько записей
///
///
+ /// комментарий
///
///
- Task UpdateRange(IEnumerable dtos, CancellationToken token);
-
- ///
- /// Удалить одну запись
- ///
- ///
- ///
- ///
- Task Delete(Guid id, CancellationToken token);
+ Task UpdateRange(IEnumerable dtos, string comment, CancellationToken token);
///
/// Удалить несколько записей
///
///
+ /// комментарий к удалению
///
///
- Task DeleteRange(IEnumerable ids, CancellationToken token);
+ Task DeleteRange(IEnumerable ids, string comment, CancellationToken token);
///
/// Получение списка дат, в которые происходили изменения (день, месяц, год, без времени)
diff --git a/DD.Persistence/Repositories/IChangeLogCommitRepository.cs b/DD.Persistence/Repositories/IChangeLogCommitRepository.cs
new file mode 100644
index 0000000..6cb1d0d
--- /dev/null
+++ b/DD.Persistence/Repositories/IChangeLogCommitRepository.cs
@@ -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;
+
+///
+/// Интерфейс для работы с коммитами журнала изменений
+///
+public interface IChangeLogCommitRepository
+{
+ ///
+ /// Добавить коммит для журнала изменений
+ ///
+ ///
+ ///
+ ///
+ Task Add(CreateChangeLogCommitRequest commitDto, CancellationToken token);
+}
diff --git a/DD.Persistence/Repositories/IChangeLogRepository.cs b/DD.Persistence/Repositories/IChangeLogRepository.cs
index 3305e65..5fd3ba6 100644
--- a/DD.Persistence/Repositories/IChangeLogRepository.cs
+++ b/DD.Persistence/Repositories/IChangeLogRepository.cs
@@ -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;
///
/// Интерфейс для работы с историческими данными
///
-///
public interface IChangeLogRepository : ISyncWithDiscriminatorRepository
{
///
/// Добавление записей
///
- /// пользователь, который добавляет
/// ключ справочника
+ /// коммит с изменениями
///
///
///
- Task AddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable dtos, CancellationToken token);
+ Task AddRange(Guid idDiscriminator, ChangeLogCommitDto dto, IEnumerable dtos, CancellationToken token);
///
/// Пометить записи как удаленные
///
- ///
+ ///
/// ключи записей
+ ///
///
///
- Task MarkAsDeleted(Guid idEditor, IEnumerable ids, CancellationToken token);
+ Task MarkAsDeleted(Guid idCommit, IEnumerable ids, DateTimeOffset updateTime, CancellationToken token);
///
/// Пометить записи как удаленные
///
- ///
/// дискриминатор таблицы
+ ///
+ ///
///
///
- Task MarkAsDeleted(Guid idEditor, Guid idDiscriminator, CancellationToken token);
+ Task MarkAsDeleted(Guid idDiscriminator, Guid idCommit, DateTimeOffset updateTime, CancellationToken token);
///
/// Очистить и добавить новые
///
- ///
///
+ /// коммит с изменениями
///
///
///
- Task ClearAndAddRange(Guid idAuthor, Guid idDiscriminator, IEnumerable dtos, CancellationToken token);
+ Task ClearAndAddRange(Guid idDiscriminator, ChangeLogCommitDto dto, IEnumerable dtos, CancellationToken token);
///
/// Редактирование записей
///
- /// пользователь, который редактирует
+ /// коммит с изменениями
///
///
///
- Task UpdateRange(Guid idEditor, IEnumerable dtos, CancellationToken token);
+ Task UpdateRange(ChangeLogCommitDto commitDto, IEnumerable dtos, CancellationToken token);
///
/// Получение актуальных записей на определенный момент времени (с пагинацией)