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); /// /// Получение актуальных записей на определенный момент времени (с пагинацией)