diff --git a/Persistence.Client/Clients/ITechMessagesClient.cs b/Persistence.Client/Clients/ITechMessagesClient.cs index 1426b54..43839fe 100644 --- a/Persistence.Client/Clients/ITechMessagesClient.cs +++ b/Persistence.Client/Clients/ITechMessagesClient.cs @@ -1,4 +1,5 @@ -using Persistence.Models; +using Microsoft.AspNetCore.Mvc; +using Persistence.Models; using Refit; namespace Persistence.Client.Clients @@ -19,7 +20,7 @@ namespace Persistence.Client.Clients [Get($"{BaseRoute}/systems")] Task>> GetSystems(CancellationToken token); - [Get($"{BaseRoute}/statistics")] - Task> GetStatistics(int importantId, string autoDrillingSystem, CancellationToken token); + [Get($"{BaseRoute}/statistics/" + "{autoDrillingSystem}")] + Task> GetStatistics(string? autoDrillingSystem, int? importantId, CancellationToken token); } } diff --git a/Persistence.Database.Postgres/Migrations/20241127123045_TechMessageMigration.Designer.cs b/Persistence.Database.Postgres/Migrations/20241128074729_TechMessageMigration.Designer.cs similarity index 98% rename from Persistence.Database.Postgres/Migrations/20241127123045_TechMessageMigration.Designer.cs rename to Persistence.Database.Postgres/Migrations/20241128074729_TechMessageMigration.Designer.cs index 2e5a30a..6678078 100644 --- a/Persistence.Database.Postgres/Migrations/20241127123045_TechMessageMigration.Designer.cs +++ b/Persistence.Database.Postgres/Migrations/20241128074729_TechMessageMigration.Designer.cs @@ -12,7 +12,7 @@ using Persistence.Database.Model; namespace Persistence.Database.Postgres.Migrations { [DbContext(typeof(PersistenceDbContext))] - [Migration("20241127123045_TechMessageMigration")] + [Migration("20241128074729_TechMessageMigration")] partial class TechMessageMigration { /// @@ -55,27 +55,27 @@ namespace Persistence.Database.Postgres.Migrations .HasColumnType("uuid") .HasComment("Id события"); + b.Property("CategoryId") + .HasColumnType("integer") + .HasComment("Id Категории важности"); + b.Property("Depth") .HasColumnType("double precision") .HasComment("Глубина забоя"); - b.Property("ImportantId") - .HasColumnType("integer") - .HasComment("Id Категории важности"); - b.Property("MessageText") .IsRequired() .HasColumnType("varchar(512)") .HasComment("Текст сообщения"); - b.Property("OccurrenceDate") - .HasColumnType("timestamp with time zone") - .HasComment("Дата возникновения"); - b.Property("SystemId") .HasColumnType("uuid") .HasComment("Id системы автобурения, к которой относится сообщение"); + b.Property("Timestamp") + .HasColumnType("timestamp with time zone") + .HasComment("Дата возникновения"); + b.Property("UserId") .HasColumnType("uuid") .HasComment("Id пользователя за пультом бурильщика"); diff --git a/Persistence.Database.Postgres/Migrations/20241127123045_TechMessageMigration.cs b/Persistence.Database.Postgres/Migrations/20241128074729_TechMessageMigration.cs similarity index 70% rename from Persistence.Database.Postgres/Migrations/20241127123045_TechMessageMigration.cs rename to Persistence.Database.Postgres/Migrations/20241128074729_TechMessageMigration.cs index d3a5ac2..047ad52 100644 --- a/Persistence.Database.Postgres/Migrations/20241127123045_TechMessageMigration.cs +++ b/Persistence.Database.Postgres/Migrations/20241128074729_TechMessageMigration.cs @@ -24,27 +24,13 @@ namespace Persistence.Database.Postgres.Migrations table.PrimaryKey("PK_ADSystem", x => x.SystemId); }); - migrationBuilder.CreateTable( - name: "TimestampedSets", - columns: table => new - { - IdDiscriminator = table.Column(type: "uuid", nullable: false, comment: "Дискриминатор ссылка на тип сохраняемых данных"), - Timestamp = table.Column(type: "timestamp with time zone", nullable: false, comment: "Отметка времени, строго в UTC"), - Set = table.Column(type: "jsonb", nullable: false, comment: "Набор сохраняемых данных") - }, - constraints: table => - { - table.PrimaryKey("PK_TimestampedSets", x => new { x.IdDiscriminator, x.Timestamp }); - }, - comment: "Общая таблица данных временных рядов"); - migrationBuilder.CreateTable( name: "TechMessage", columns: table => new { EventId = table.Column(type: "uuid", nullable: false, comment: "Id события"), - ImportantId = table.Column(type: "integer", nullable: false, comment: "Id Категории важности"), - OccurrenceDate = table.Column(type: "timestamp with time zone", nullable: false, comment: "Дата возникновения"), + CategoryId = table.Column(type: "integer", nullable: false, comment: "Id Категории важности"), + Timestamp = table.Column(type: "timestamp with time zone", nullable: false, comment: "Дата возникновения"), Depth = table.Column(type: "double precision", nullable: true, comment: "Глубина забоя"), MessageText = table.Column(type: "varchar(512)", nullable: false, comment: "Текст сообщения"), SystemId = table.Column(type: "uuid", nullable: false, comment: "Id системы автобурения, к которой относится сообщение"), @@ -73,9 +59,6 @@ namespace Persistence.Database.Postgres.Migrations migrationBuilder.DropTable( name: "TechMessage"); - migrationBuilder.DropTable( - name: "TimestampedSets"); - migrationBuilder.DropTable( name: "ADSystem"); } diff --git a/Persistence.Database.Postgres/Migrations/PersistenceDbContextModelSnapshot.cs b/Persistence.Database.Postgres/Migrations/PersistenceDbContextModelSnapshot.cs index 317c445..f5533cc 100644 --- a/Persistence.Database.Postgres/Migrations/PersistenceDbContextModelSnapshot.cs +++ b/Persistence.Database.Postgres/Migrations/PersistenceDbContextModelSnapshot.cs @@ -52,27 +52,27 @@ namespace Persistence.Database.Postgres.Migrations .HasColumnType("uuid") .HasComment("Id события"); + b.Property("CategoryId") + .HasColumnType("integer") + .HasComment("Id Категории важности"); + b.Property("Depth") .HasColumnType("double precision") .HasComment("Глубина забоя"); - b.Property("ImportantId") - .HasColumnType("integer") - .HasComment("Id Категории важности"); - b.Property("MessageText") .IsRequired() .HasColumnType("varchar(512)") .HasComment("Текст сообщения"); - b.Property("OccurrenceDate") - .HasColumnType("timestamp with time zone") - .HasComment("Дата возникновения"); - b.Property("SystemId") .HasColumnType("uuid") .HasComment("Id системы автобурения, к которой относится сообщение"); + b.Property("Timestamp") + .HasColumnType("timestamp with time zone") + .HasComment("Дата возникновения"); + b.Property("UserId") .HasColumnType("uuid") .HasComment("Id пользователя за пультом бурильщика"); diff --git a/Persistence.Database.Postgres/PersistenceDbContext.cs b/Persistence.Database.Postgres/PersistenceDbContext.cs index f9f9a16..89b09db 100644 --- a/Persistence.Database.Postgres/PersistenceDbContext.cs +++ b/Persistence.Database.Postgres/PersistenceDbContext.cs @@ -12,7 +12,7 @@ public partial class PersistenceDbContext : DbContext public DbSet TechMessage => Set(); - public DbSet TimestampedSets => Set(); + public DbSet TimestampedSets => Set(); public PersistenceDbContext() : base() @@ -42,5 +42,14 @@ public partial class PersistenceDbContext : DbContext modelBuilder.Entity() .Property(e => e.Set) .HasJsonConversion(); - } + + modelBuilder.Entity(entity => + { + entity.HasOne(t => t.System) + .WithMany() + .HasForeignKey(t => t.SystemId) + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + } } diff --git a/Persistence.Database/Entity/TechMessage.cs b/Persistence.Database/Entity/TechMessage.cs index dce897c..eacc234 100644 --- a/Persistence.Database/Entity/TechMessage.cs +++ b/Persistence.Database/Entity/TechMessage.cs @@ -10,10 +10,10 @@ namespace Persistence.Database.Entity public Guid EventId { get; set; } [Comment("Id Категории важности")] - public int ImportantId { get; set; } + public int CategoryId { get; set; } [Comment("Дата возникновения")] - public DateTimeOffset OccurrenceDate { get; set; } + public DateTimeOffset Timestamp { get; set; } [Comment("Глубина забоя")] public double? Depth { get; set; } diff --git a/Persistence.IntegrationTests/Controllers/TechMessagesControllerTest.cs b/Persistence.IntegrationTests/Controllers/TechMessagesControllerTest.cs index 73414c4..3902681 100644 --- a/Persistence.IntegrationTests/Controllers/TechMessagesControllerTest.cs +++ b/Persistence.IntegrationTests/Controllers/TechMessagesControllerTest.cs @@ -1,4 +1,5 @@ using System.Net; +using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Persistence.Client; using Persistence.Client.Clients; @@ -10,7 +11,9 @@ namespace Persistence.IntegrationTests.Controllers { public class TechMessagesControllerTest : BaseIntegrationTest { + private static readonly string SystemCacheKey = $"{typeof(ADSystem).FullName}CacheKey"; private readonly ITechMessagesClient techMessagesClient; + private readonly IMemoryCache memoryCache; public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory) { var scope = factory.Services.CreateScope(); @@ -18,6 +21,7 @@ namespace Persistence.IntegrationTests.Controllers .GetRequiredService(); techMessagesClient = persistenceClientFactory.GetClient(); + memoryCache = scope.ServiceProvider.GetRequiredService(); } [Fact] @@ -29,7 +33,7 @@ namespace Persistence.IntegrationTests.Controllers { Skip = 1, Take = 2, - SortSettings = nameof(TechMessageDto.CategoryId) + SortSettings = nameof(TechMessage.CategoryId) }; //act @@ -53,7 +57,7 @@ namespace Persistence.IntegrationTests.Controllers { Skip = 0, Take = 2, - SortSettings = nameof(TechMessageDto.CategoryId) + SortSettings = nameof(TechMessage.CategoryId) }; //act @@ -71,11 +75,39 @@ namespace Persistence.IntegrationTests.Controllers await InsertRange(); } + [Fact] + public async Task InsertRange_returns_BadRequest() + { + //arrange + var dtos = new List() + { + new TechMessageDto() + { + EventId = Guid.NewGuid(), + CategoryId = -1, // < 0 + Timestamp = DateTimeOffset.UtcNow, + Depth = -1, // < 0 + MessageText = string.Empty, // length < 0 + System = string.Concat(Enumerable.Repeat(nameof(TechMessageDto.System), 100)), // length > 256 + UserId = Guid.NewGuid() + } + }; + + //act + var response = await techMessagesClient.InsertRange(dtos, new CancellationToken()); + + //assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + } + [Fact] public async Task GetSystems_returns_success() { + //arrange + dbContext.CleanupDbSet(); + memoryCache.Remove(SystemCacheKey); + //act - dbContext.CleanupDbSet(); var response = await techMessagesClient.GetSystems(new CancellationToken()); //assert @@ -113,7 +145,7 @@ namespace Persistence.IntegrationTests.Controllers var autoDrillingSystem = nameof(TechMessageDto.System); //act - var response = await techMessagesClient.GetStatistics(imortantId, autoDrillingSystem, new CancellationToken()); + var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken()); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -124,13 +156,13 @@ namespace Persistence.IntegrationTests.Controllers public async Task GetStatistics_AfterSave_returns_success() { //arrange - var imortantId = 1; + var imortantId = 0; var autoDrillingSystem = nameof(TechMessageDto.System); var dtos = await InsertRange(); var filteredDtos = dtos.Where(e => e.CategoryId == imortantId && e.System == e.System); //act - var response = await techMessagesClient.GetStatistics(imortantId, autoDrillingSystem, new CancellationToken()); + var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken()); //assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); diff --git a/Persistence.Repository/Repositories/TechMessagesRepository.cs b/Persistence.Repository/Repositories/TechMessagesRepository.cs index 427346b..478ba0f 100644 --- a/Persistence.Repository/Repositories/TechMessagesRepository.cs +++ b/Persistence.Repository/Repositories/TechMessagesRepository.cs @@ -1,7 +1,6 @@ using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; -using Newtonsoft.Json.Linq; using Persistence.Database.Entity; using Persistence.Models; using Persistence.Repositories; @@ -21,7 +20,8 @@ namespace Persistence.Repository.Repositories this.db = db; } - protected virtual IQueryable GetQueryReadOnly() => db.Set(); + protected virtual IQueryable GetQueryReadOnly() => db.Set() + .Include(e => e.System); public async Task> GetPage(RequestDto request, CancellationToken token) { @@ -46,7 +46,7 @@ namespace Persistence.Repository.Repositories { var query = GetQueryReadOnly(); var count = await query - .Where(e => importantId == null || e.ImportantId == importantId) + .Where(e => importantId == null || e.CategoryId == importantId) .Where(e => autoDrillingSystem == null || e.System.Name == autoDrillingSystem) .GroupBy(e => e.System.Name) .ToDictionaryAsync(e => e.Key, v => v.Count()); @@ -54,7 +54,37 @@ namespace Persistence.Repository.Repositories return count; } - public async Task> GetSystems(CancellationToken token) + public async Task> GetSystems(CancellationToken token) + { + var entities = await GetSystems(); + var systems = entities.Select(e => e.Name); + + return systems ?? []; + } + + public async Task InsertRange(IEnumerable dtos, CancellationToken token) + { + + var entities = new List(); + foreach (var dto in dtos) + { + var entity = dto.Adapt(); + var systems = await GetSystems(); + var systemId = systems.FirstOrDefault(e => e.Name == dto.System)?.SystemId + ?? await CreateSystem(dto.System); + + entity.SystemId = systemId; + + entities.Add(entity); + } + + await db.Set().AddRangeAsync(entities, token); + var result = await db.SaveChangesAsync(token); + + return result; + } + + private async Task> GetSystems() { var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f => { @@ -69,33 +99,6 @@ namespace Persistence.Repository.Repositories return systems ?? []; } - - public async Task InsertRange(IEnumerable dtos, CancellationToken token) - { - var entities = dtos.Select(dto => - { - var task = Task.Run(async () => - { - var entity = dto.Adapt(); - var systems = await GetSystems(token); - var systemId = systems.FirstOrDefault(e => e.Name == dto.System)?.SystemId - ?? await CreateSystem(dto.System); - - entity.SystemId = systemId; - - return entity; - }); - task.Wait(); - - return task.Result; - }); - - await db.Set().AddRangeAsync(entities, token); - var result = await db.SaveChangesAsync(token); - - return result; - } - private async Task CreateSystem(string name) { memoryCache.Remove(SystemCacheKey); @@ -110,7 +113,7 @@ namespace Persistence.Repository.Repositories await db.Set().AddAsync(entity); await db.SaveChangesAsync(); - return Guid.NewGuid(); + return systemId; } } } diff --git a/Persistence/Repositories/ITechMessagesRepository.cs b/Persistence/Repositories/ITechMessagesRepository.cs index b8fb194..74b2bf5 100644 --- a/Persistence/Repositories/ITechMessagesRepository.cs +++ b/Persistence/Repositories/ITechMessagesRepository.cs @@ -29,7 +29,7 @@ namespace Persistence.Repositories /// /// /// - Task> GetSystems(CancellationToken token); + Task> GetSystems(CancellationToken token); /// /// Получение количества сообщений по категориям и системам автобурения