Изменить TechMessagesRepository, добавить тестирование валидации
This commit is contained in:
parent
1e87523ab9
commit
097b422310
@ -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<IApiResponse<IEnumerable<string>>> GetSystems(CancellationToken token);
|
||||
|
||||
[Get($"{BaseRoute}/statistics")]
|
||||
Task<IApiResponse<int>> GetStatistics(int importantId, string autoDrillingSystem, CancellationToken token);
|
||||
[Get($"{BaseRoute}/statistics/" + "{autoDrillingSystem}")]
|
||||
Task<IApiResponse<int>> GetStatistics(string? autoDrillingSystem, int? importantId, CancellationToken token);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
/// <inheritdoc />
|
||||
@ -55,27 +55,27 @@ namespace Persistence.Database.Postgres.Migrations
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id события");
|
||||
|
||||
b.Property<int>("CategoryId")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Id Категории важности");
|
||||
|
||||
b.Property<double?>("Depth")
|
||||
.HasColumnType("double precision")
|
||||
.HasComment("Глубина забоя");
|
||||
|
||||
b.Property<int>("ImportantId")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Id Категории важности");
|
||||
|
||||
b.Property<string>("MessageText")
|
||||
.IsRequired()
|
||||
.HasColumnType("varchar(512)")
|
||||
.HasComment("Текст сообщения");
|
||||
|
||||
b.Property<DateTimeOffset>("OccurrenceDate")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата возникновения");
|
||||
|
||||
b.Property<Guid>("SystemId")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id системы автобурения, к которой относится сообщение");
|
||||
|
||||
b.Property<DateTimeOffset>("Timestamp")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата возникновения");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id пользователя за пультом бурильщика");
|
@ -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<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор ссылка на тип сохраняемых данных"),
|
||||
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Отметка времени, строго в UTC"),
|
||||
Set = table.Column<string>(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<Guid>(type: "uuid", nullable: false, comment: "Id события"),
|
||||
ImportantId = table.Column<int>(type: "integer", nullable: false, comment: "Id Категории важности"),
|
||||
OccurrenceDate = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата возникновения"),
|
||||
CategoryId = table.Column<int>(type: "integer", nullable: false, comment: "Id Категории важности"),
|
||||
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата возникновения"),
|
||||
Depth = table.Column<double>(type: "double precision", nullable: true, comment: "Глубина забоя"),
|
||||
MessageText = table.Column<string>(type: "varchar(512)", nullable: false, comment: "Текст сообщения"),
|
||||
SystemId = table.Column<Guid>(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");
|
||||
}
|
@ -52,27 +52,27 @@ namespace Persistence.Database.Postgres.Migrations
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id события");
|
||||
|
||||
b.Property<int>("CategoryId")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Id Категории важности");
|
||||
|
||||
b.Property<double?>("Depth")
|
||||
.HasColumnType("double precision")
|
||||
.HasComment("Глубина забоя");
|
||||
|
||||
b.Property<int>("ImportantId")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Id Категории важности");
|
||||
|
||||
b.Property<string>("MessageText")
|
||||
.IsRequired()
|
||||
.HasColumnType("varchar(512)")
|
||||
.HasComment("Текст сообщения");
|
||||
|
||||
b.Property<DateTimeOffset>("OccurrenceDate")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата возникновения");
|
||||
|
||||
b.Property<Guid>("SystemId")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id системы автобурения, к которой относится сообщение");
|
||||
|
||||
b.Property<DateTimeOffset>("Timestamp")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("Дата возникновения");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasComment("Id пользователя за пультом бурильщика");
|
||||
|
@ -12,7 +12,7 @@ public partial class PersistenceDbContext : DbContext
|
||||
|
||||
public DbSet<TechMessage> TechMessage => Set<TechMessage>();
|
||||
|
||||
public DbSet<TimestampedSet> TimestampedSets => Set<TimestampedSet>();
|
||||
public DbSet<TimestampedSet> TimestampedSets => Set<TimestampedSet>();
|
||||
|
||||
public PersistenceDbContext()
|
||||
: base()
|
||||
@ -42,5 +42,14 @@ public partial class PersistenceDbContext : DbContext
|
||||
modelBuilder.Entity<TimestampedSet>()
|
||||
.Property(e => e.Set)
|
||||
.HasJsonConversion();
|
||||
}
|
||||
|
||||
modelBuilder.Entity<TechMessage>(entity =>
|
||||
{
|
||||
entity.HasOne(t => t.System)
|
||||
.WithMany()
|
||||
.HasForeignKey(t => t.SystemId)
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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<PersistenceClientFactory>();
|
||||
|
||||
techMessagesClient = persistenceClientFactory.GetClient<ITechMessagesClient>();
|
||||
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||
}
|
||||
|
||||
[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<TechMessageDto>()
|
||||
{
|
||||
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<ADSystem>();
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
|
||||
//act
|
||||
dbContext.CleanupDbSet<TechMessage>();
|
||||
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);
|
||||
|
@ -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<TechMessage> GetQueryReadOnly() => db.Set<TechMessage>();
|
||||
protected virtual IQueryable<TechMessage> GetQueryReadOnly() => db.Set<TechMessage>()
|
||||
.Include(e => e.System);
|
||||
|
||||
public async Task<PaginationContainer<TechMessageDto>> 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<IEnumerable<ADSystemDto>> GetSystems(CancellationToken token)
|
||||
public async Task<IEnumerable<string>> GetSystems(CancellationToken token)
|
||||
{
|
||||
var entities = await GetSystems();
|
||||
var systems = entities.Select(e => e.Name);
|
||||
|
||||
return systems ?? [];
|
||||
}
|
||||
|
||||
public async Task<int> InsertRange(IEnumerable<TechMessageDto> dtos, CancellationToken token)
|
||||
{
|
||||
|
||||
var entities = new List<TechMessage>();
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
var entity = dto.Adapt<TechMessage>();
|
||||
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<TechMessage>().AddRangeAsync(entities, token);
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<ADSystemDto>> GetSystems()
|
||||
{
|
||||
var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f =>
|
||||
{
|
||||
@ -69,33 +99,6 @@ namespace Persistence.Repository.Repositories
|
||||
|
||||
return systems ?? [];
|
||||
}
|
||||
|
||||
public async Task<int> InsertRange(IEnumerable<TechMessageDto> dtos, CancellationToken token)
|
||||
{
|
||||
var entities = dtos.Select(dto =>
|
||||
{
|
||||
var task = Task.Run(async () =>
|
||||
{
|
||||
var entity = dto.Adapt<TechMessage>();
|
||||
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<TechMessage>().AddRangeAsync(entities, token);
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Guid> CreateSystem(string name)
|
||||
{
|
||||
memoryCache.Remove(SystemCacheKey);
|
||||
@ -110,7 +113,7 @@ namespace Persistence.Repository.Repositories
|
||||
await db.Set<ADSystem>().AddAsync(entity);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Guid.NewGuid();
|
||||
return systemId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<ADSystemDto>> GetSystems(CancellationToken token);
|
||||
Task<IEnumerable<string>> GetSystems(CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение количества сообщений по категориям и системам автобурения
|
||||
|
Loading…
Reference in New Issue
Block a user