Reviewed-on: #4
This commit is contained in:
commit
6f93c331a2
@ -4,6 +4,10 @@ using Persistence.Repositories;
|
|||||||
using Persistence.Repository.Data;
|
using Persistence.Repository.Data;
|
||||||
|
|
||||||
namespace Persistence.API.Controllers;
|
namespace Persistence.API.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Работа с временными данными
|
||||||
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
using Persistence.Repositories;
|
using Persistence.Repositories;
|
||||||
|
|
||||||
namespace Persistence.API.Controllers
|
namespace Persistence.API.Controllers;
|
||||||
{
|
|
||||||
|
/// <summary>
|
||||||
|
/// Работа с уставками
|
||||||
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
@ -17,6 +21,12 @@ namespace Persistence.API.Controllers
|
|||||||
this.setpointRepository = setpointRepository;
|
this.setpointRepository = setpointRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить актуальные значения уставок
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="setpointKeys"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpGet("current")]
|
[HttpGet("current")]
|
||||||
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrent([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrent([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||||
{
|
{
|
||||||
@ -25,6 +35,13 @@ namespace Persistence.API.Controllers
|
|||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить значения уставок за определенный момент времени
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="setpointKeys"></param>
|
||||||
|
/// <param name="historyMoment"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpGet("history")]
|
[HttpGet("history")]
|
||||||
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetHistory([FromQuery] IEnumerable<Guid> setpointKeys, [FromQuery] DateTimeOffset historyMoment, CancellationToken token)
|
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetHistory([FromQuery] IEnumerable<Guid> setpointKeys, [FromQuery] DateTimeOffset historyMoment, CancellationToken token)
|
||||||
{
|
{
|
||||||
@ -33,6 +50,12 @@ namespace Persistence.API.Controllers
|
|||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить историю изменений значений уставок
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="setpointKeys"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpGet("log")]
|
[HttpGet("log")]
|
||||||
public async Task<ActionResult<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
public async Task<ActionResult<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||||
{
|
{
|
||||||
@ -41,13 +64,49 @@ namespace Persistence.API.Controllers
|
|||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
/// <summary>
|
||||||
public async Task<ActionResult<int>> Save(Guid setpointKey, object newValue, CancellationToken token)
|
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("range")]
|
||||||
|
public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
// ToDo: вычитка idUser
|
var result = await setpointRepository.GetDatesRangeAsync(token);
|
||||||
await setpointRepository.Save(setpointKey, newValue, 0, token);
|
|
||||||
|
|
||||||
return Ok();
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить порцию записей, начиная с заданной даты
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateBegin"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("part")]
|
||||||
|
public async Task<ActionResult<IEnumerable<SetpointLogDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await setpointRepository.GetPart(dateBegin, take, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сохранить уставку
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="setpointKey"></param>
|
||||||
|
/// <param name="newValue"></param>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||||
|
public async Task<IActionResult> Add(Guid setpointKey, object newValue, CancellationToken token)
|
||||||
|
{
|
||||||
|
var userId = User.GetUserId<Guid>();
|
||||||
|
await setpointRepository.Add(setpointKey, newValue, userId, token);
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(Add), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
128
Persistence.API/Controllers/TechMessagesController.cs
Normal file
128
Persistence.API/Controllers/TechMessagesController.cs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Persistence.Models;
|
||||||
|
using Persistence.Repositories;
|
||||||
|
|
||||||
|
namespace Persistence.API.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Работа с состояниями систем автобурения (АБ)
|
||||||
|
/// </summary>
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class TechMessagesController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ITechMessagesRepository techMessagesRepository;
|
||||||
|
private static readonly Dictionary<int, string> categories = new Dictionary<int, string>()
|
||||||
|
{
|
||||||
|
{ 0, "System" },
|
||||||
|
{ 1, "Авария" },
|
||||||
|
{ 2, "Предупреждение" },
|
||||||
|
{ 3, "Инфо" },
|
||||||
|
{ 4, "Прочее" }
|
||||||
|
};
|
||||||
|
|
||||||
|
public TechMessagesController(ITechMessagesRepository techMessagesRepository)
|
||||||
|
{
|
||||||
|
this.techMessagesRepository = techMessagesRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить список технологических сообщений в виде страницы
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<PaginationContainer<TechMessageDto>>> GetPage([FromQuery] RequestDto request, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await techMessagesRepository.GetPage(request, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить статистику по системам
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="autoDrillingSystem"></param>
|
||||||
|
/// <param name="categoryIds"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("statistics")]
|
||||||
|
public async Task<ActionResult<IEnumerable<MessagesStatisticDto>>> GetStatistics([FromQuery] IEnumerable<string> autoDrillingSystem, [FromQuery] IEnumerable<int> categoryIds, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await techMessagesRepository.GetStatistics(autoDrillingSystem, categoryIds, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить список всех систем
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("systems")]
|
||||||
|
public async Task<ActionResult<Dictionary<string, int>>> GetSystems(CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await techMessagesRepository.GetSystems(token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("range")]
|
||||||
|
public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await techMessagesRepository.GetDatesRangeAsync(token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить порцию записей, начиная с заданной даты
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateBegin"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("part")]
|
||||||
|
public async Task<ActionResult<IEnumerable<SetpointLogDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await techMessagesRepository.GetPart(dateBegin, take, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить новые технологические сообщения
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dtos"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||||
|
public async Task<IActionResult> AddRange([FromBody] IEnumerable<TechMessageDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
var userId = User.GetUserId<Guid>();
|
||||||
|
|
||||||
|
var result = await techMessagesRepository.AddRange(dtos, userId, token);
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(AddRange), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить словарь категорий
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("categories")]
|
||||||
|
public ActionResult<Dictionary<int, string>> GetImportantCategories()
|
||||||
|
{
|
||||||
|
return Ok(categories);
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ using Persistence.Models;
|
|||||||
using Persistence.Repositories;
|
using Persistence.Repositories;
|
||||||
|
|
||||||
namespace Persistence.API.Controllers;
|
namespace Persistence.API.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
@ -17,32 +18,57 @@ public class TimeSeriesController<TDto> : ControllerBase, ITimeSeriesDataApi<TDt
|
|||||||
this.timeSeriesDataRepository = timeSeriesDataRepository;
|
this.timeSeriesDataRepository = timeSeriesDataRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить список объектов, удовлетворяющий диапазону дат
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateBegin"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
public async Task<IActionResult> Get(DateTimeOffset dateBegin, CancellationToken token)
|
public async Task<IActionResult> Get(DateTimeOffset dateBegin, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await this.timeSeriesDataRepository.GetGtDate(dateBegin, token);
|
var result = await timeSeriesDataRepository.GetGtDate(dateBegin, token);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить диапазон дат, для которых есть данные в репозиторие
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpGet("datesRange")]
|
[HttpGet("datesRange")]
|
||||||
public async Task<IActionResult> GetDatesRange(CancellationToken token)
|
public async Task<IActionResult> GetDatesRange(CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await this.timeSeriesDataRepository.GetDatesRange(token);
|
var result = await timeSeriesDataRepository.GetDatesRange(token);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить список объектов с прореживанием, удовлетворяющий диапазону дат
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateBegin"></param>
|
||||||
|
/// <param name="intervalSec"></param>
|
||||||
|
/// <param name="approxPointsCount"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpGet("resampled")]
|
[HttpGet("resampled")]
|
||||||
public async Task<IActionResult> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default)
|
public async Task<IActionResult> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var result = await this.timeSeriesDataRepository.GetResampledData(dateBegin, intervalSec, approxPointsCount, token);
|
var result = await timeSeriesDataRepository.GetResampledData(dateBegin, intervalSec, approxPointsCount, token);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить записи
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dtos"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> InsertRange(IEnumerable<TDto> dtos, CancellationToken token)
|
public async Task<IActionResult> AddRange(IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await this.timeSeriesDataRepository.InsertRange(dtos, token);
|
var result = await timeSeriesDataRepository.AddRange(dtos, token);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ public class TimestampedSetController : ControllerBase
|
|||||||
/// <returns>кол-во затронутых записей</returns>
|
/// <returns>кол-во затронутых записей</returns>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
||||||
public async Task<IActionResult> InsertRange([FromRoute]Guid idDiscriminator, [FromBody]IEnumerable<TimestampedSetDto> sets, CancellationToken token)
|
public async Task<IActionResult> AddRange([FromRoute]Guid idDiscriminator, [FromBody]IEnumerable<TimestampedSetDto> sets, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await repository.InsertRange(idDiscriminator, sets, token);
|
var result = await repository.AddRange(idDiscriminator, sets, token);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
|
using System.Reflection;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
|
using Mapster;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi.Any;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Persistence.Database.Entity;
|
||||||
|
using Persistence.Models;
|
||||||
using Persistence.Models.Configurations;
|
using Persistence.Models.Configurations;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
@ -10,6 +14,12 @@ namespace Persistence.API;
|
|||||||
|
|
||||||
public static class DependencyInjection
|
public static class DependencyInjection
|
||||||
{
|
{
|
||||||
|
public static void MapsterSetup()
|
||||||
|
{
|
||||||
|
TypeAdapterConfig.GlobalSettings.Default.Config
|
||||||
|
.ForType<TechMessageDto, TechMessage>()
|
||||||
|
.Ignore(dest => dest.System, dest => dest.SystemId);
|
||||||
|
}
|
||||||
public static void AddSwagger(this IServiceCollection services, IConfiguration configuration)
|
public static void AddSwagger(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
services.AddSwaggerGen(c =>
|
services.AddSwaggerGen(c =>
|
||||||
@ -38,11 +48,10 @@ public static class DependencyInjection
|
|||||||
c.AddKeycloackSecurity(configuration);
|
c.AddKeycloackSecurity(configuration);
|
||||||
else c.AddDefaultSecurity(configuration);
|
else c.AddDefaultSecurity(configuration);
|
||||||
|
|
||||||
//var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||||
//var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||||
//var includeControllerXmlComment = true;
|
var includeControllerXmlComment = true;
|
||||||
//options.IncludeXmlComments(xmlPath, includeControllerXmlComment);
|
c.IncludeXmlComments(xmlPath, includeControllerXmlComment);
|
||||||
//options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AsbCloudApp.xml"), includeControllerXmlComment);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,13 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
|
||||||
|
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -23,6 +23,9 @@ public class Startup
|
|||||||
services.AddInfrastructure();
|
services.AddInfrastructure();
|
||||||
services.AddPersistenceDbContext(Configuration);
|
services.AddPersistenceDbContext(Configuration);
|
||||||
services.AddJWTAuthentication(Configuration);
|
services.AddJWTAuthentication(Configuration);
|
||||||
|
services.AddMemoryCache();
|
||||||
|
|
||||||
|
DependencyInjection.MapsterSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
@ -4,7 +4,7 @@ using Refit;
|
|||||||
namespace Persistence.Client.Clients;
|
namespace Persistence.Client.Clients;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Интерфейс для тестирования API, предназначенного для работы с уставками
|
/// Интерфейс клиента для работы с уставками
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISetpointClient
|
public interface ISetpointClient
|
||||||
{
|
{
|
||||||
@ -19,6 +19,12 @@ public interface ISetpointClient
|
|||||||
[Get($"{BaseRoute}/log")]
|
[Get($"{BaseRoute}/log")]
|
||||||
Task<IApiResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys);
|
Task<IApiResponse<Dictionary<Guid, IEnumerable<SetpointLogDto>>>> GetLog([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys);
|
||||||
|
|
||||||
|
[Get($"{BaseRoute}/range")]
|
||||||
|
Task<IApiResponse<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token);
|
||||||
|
|
||||||
|
[Get($"{BaseRoute}/part")]
|
||||||
|
Task<IApiResponse<IEnumerable<SetpointLogDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
|
||||||
|
|
||||||
[Post($"{BaseRoute}/")]
|
[Post($"{BaseRoute}/")]
|
||||||
Task<IApiResponse> Save(Guid setpointKey, object newValue);
|
Task<IApiResponse> Add(Guid setpointKey, object newValue);
|
||||||
}
|
}
|
||||||
|
31
Persistence.Client/Clients/ITechMessagesClient.cs
Normal file
31
Persistence.Client/Clients/ITechMessagesClient.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using Persistence.Models;
|
||||||
|
using Refit;
|
||||||
|
|
||||||
|
namespace Persistence.Client.Clients
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Интерфейс клиента для хранения технологических сообщений
|
||||||
|
/// </summary>
|
||||||
|
public interface ITechMessagesClient
|
||||||
|
{
|
||||||
|
private const string BaseRoute = "/api/techMessages";
|
||||||
|
|
||||||
|
[Get($"{BaseRoute}")]
|
||||||
|
Task<IApiResponse<PaginationContainer<TechMessageDto>>> GetPage([Query] RequestDto request, CancellationToken token);
|
||||||
|
|
||||||
|
[Post($"{BaseRoute}")]
|
||||||
|
Task<IApiResponse<int>> AddRange([Body] IEnumerable<TechMessageDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
|
[Get($"{BaseRoute}/systems")]
|
||||||
|
Task<IApiResponse<IEnumerable<string>>> GetSystems(CancellationToken token);
|
||||||
|
|
||||||
|
[Get($"{BaseRoute}/range")]
|
||||||
|
Task<IApiResponse<DatesRangeDto>> GetDatesRangeAsync(CancellationToken token);
|
||||||
|
|
||||||
|
[Get($"{BaseRoute}/part")]
|
||||||
|
Task<IApiResponse<IEnumerable<TechMessageDto>>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
|
||||||
|
|
||||||
|
[Get($"{BaseRoute}/statistics")]
|
||||||
|
Task<IApiResponse<IEnumerable<MessagesStatisticDto>>> GetStatistics([Query] string autoDrillingSystem, [Query] int categoryId, CancellationToken token);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Persistence.Models;
|
||||||
using Persistence.Models;
|
|
||||||
using Refit;
|
using Refit;
|
||||||
|
|
||||||
namespace Persistence.Client.Clients;
|
namespace Persistence.Client.Clients;
|
||||||
@ -9,7 +8,7 @@ public interface ITimeSeriesClient<TDto>
|
|||||||
private const string BaseRoute = "/api/dataSaub";
|
private const string BaseRoute = "/api/dataSaub";
|
||||||
|
|
||||||
[Post($"{BaseRoute}")]
|
[Post($"{BaseRoute}")]
|
||||||
Task<IApiResponse<int>> InsertRange(IEnumerable<TDto> dtos);
|
Task<IApiResponse<int>> AddRange(IEnumerable<TDto> dtos);
|
||||||
|
|
||||||
[Get($"{BaseRoute}")]
|
[Get($"{BaseRoute}")]
|
||||||
Task<IApiResponse<IEnumerable<TDto>>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd);
|
Task<IApiResponse<IEnumerable<TDto>>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd);
|
||||||
|
@ -20,7 +20,7 @@ public interface ITimestampedSetClient
|
|||||||
/// <param name="sets"></param>
|
/// <param name="sets"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[Post(baseUrl)]
|
[Post(baseUrl)]
|
||||||
Task<IApiResponse<int>> InsertRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets);
|
Task<IApiResponse<int>> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение данных с фильтрацией. Значение фильтра null - отключен
|
/// Получение данных с фильтрацией. Значение фильтра null - отключен
|
||||||
|
@ -29,8 +29,10 @@ public static class ApiTokenHelper
|
|||||||
|
|
||||||
private static string CreateDefaultJwtToken(this AuthUser authUser)
|
private static string CreateDefaultJwtToken(this AuthUser authUser)
|
||||||
{
|
{
|
||||||
|
var nameIdetifier = Guid.NewGuid().ToString();
|
||||||
var claims = new List<Claim>()
|
var claims = new List<Claim>()
|
||||||
{
|
{
|
||||||
|
new(ClaimTypes.NameIdentifier, nameIdetifier),
|
||||||
new("client_id", authUser.ClientId),
|
new("client_id", authUser.ClientId),
|
||||||
new("username", authUser.Username),
|
new("username", authUser.Username),
|
||||||
new("password", authUser.Password),
|
new("password", authUser.Password),
|
||||||
|
@ -18,7 +18,7 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
Key = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ"),
|
Key = table.Column<Guid>(type: "uuid", nullable: false, comment: "Ключ"),
|
||||||
Created = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата изменения уставки"),
|
Created = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата изменения уставки"),
|
||||||
Value = table.Column<object>(type: "jsonb", nullable: false, comment: "Значение уставки"),
|
Value = table.Column<object>(type: "jsonb", nullable: false, comment: "Значение уставки"),
|
||||||
IdUser = table.Column<int>(type: "integer", nullable: false, comment: "Id автора последнего изменения")
|
IdUser = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id автора последнего изменения")
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
|
233
Persistence.Database.Postgres/Migrations/20241202072250_TechMessageMigration.Designer.cs
generated
Normal file
233
Persistence.Database.Postgres/Migrations/20241202072250_TechMessageMigration.Designer.cs
generated
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
using Persistence.Database.Model;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Persistence.Database.Postgres.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(PersistenceDbContext))]
|
||||||
|
[Migration("20241202072250_TechMessageMigration")]
|
||||||
|
partial class TechMessageMigration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.UseCollation("Russian_Russia.1251")
|
||||||
|
.HasAnnotation("ProductVersion", "8.0.10")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Entity.DrillingSystem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("SystemId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Id системы автобурения");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasComment("Описание системы автобурения");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(256)")
|
||||||
|
.HasComment("Наименование системы автобурения");
|
||||||
|
|
||||||
|
b.HasKey("SystemId");
|
||||||
|
|
||||||
|
b.ToTable("DrillingSystem");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("EventId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Id события");
|
||||||
|
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("Id Категории важности");
|
||||||
|
|
||||||
|
b.Property<double?>("Depth")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasComment("Глубина забоя");
|
||||||
|
|
||||||
|
b.Property<string>("MessageText")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(512)")
|
||||||
|
.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 пользователя за пультом бурильщика");
|
||||||
|
|
||||||
|
b.HasKey("EventId");
|
||||||
|
|
||||||
|
b.HasIndex("SystemId");
|
||||||
|
|
||||||
|
b.ToTable("TechMessage");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Entity.TimestampedSet", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("IdDiscriminator")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Дискриминатор ссылка на тип сохраняемых данных");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Timestamp")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("Отметка времени, строго в UTC");
|
||||||
|
|
||||||
|
b.Property<string>("Set")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasComment("Набор сохраняемых данных");
|
||||||
|
|
||||||
|
b.HasKey("IdDiscriminator", "Timestamp");
|
||||||
|
|
||||||
|
b.ToTable("TimestampedSets", t =>
|
||||||
|
{
|
||||||
|
t.HasComment("Общая таблица данных временных рядов");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
|
||||||
|
{
|
||||||
|
b.Property<DateTimeOffset>("Date")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("date");
|
||||||
|
|
||||||
|
b.Property<double?>("AxialLoad")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("axialLoad");
|
||||||
|
|
||||||
|
b.Property<double?>("BitDepth")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("bitDepth");
|
||||||
|
|
||||||
|
b.Property<double?>("BlockPosition")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("blockPosition");
|
||||||
|
|
||||||
|
b.Property<double?>("BlockSpeed")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("blockSpeed");
|
||||||
|
|
||||||
|
b.Property<double?>("Flow")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("flow");
|
||||||
|
|
||||||
|
b.Property<double?>("HookWeight")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("hookWeight");
|
||||||
|
|
||||||
|
b.Property<int>("IdFeedRegulator")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("idFeedRegulator");
|
||||||
|
|
||||||
|
b.Property<int?>("Mode")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("mode");
|
||||||
|
|
||||||
|
b.Property<double?>("Mse")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("mse");
|
||||||
|
|
||||||
|
b.Property<short>("MseState")
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("mseState");
|
||||||
|
|
||||||
|
b.Property<double?>("Pressure")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("pressure");
|
||||||
|
|
||||||
|
b.Property<double?>("Pump0Flow")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("pump0Flow");
|
||||||
|
|
||||||
|
b.Property<double?>("Pump1Flow")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("pump1Flow");
|
||||||
|
|
||||||
|
b.Property<double?>("Pump2Flow")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("pump2Flow");
|
||||||
|
|
||||||
|
b.Property<double?>("RotorSpeed")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("rotorSpeed");
|
||||||
|
|
||||||
|
b.Property<double?>("RotorTorque")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("rotorTorque");
|
||||||
|
|
||||||
|
b.Property<string>("User")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("user");
|
||||||
|
|
||||||
|
b.Property<double?>("WellDepth")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("wellDepth");
|
||||||
|
|
||||||
|
b.HasKey("Date");
|
||||||
|
|
||||||
|
b.ToTable("DataSaub");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Model.Setpoint", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Key")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Ключ");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("Дата создания уставки");
|
||||||
|
|
||||||
|
b.Property<Guid>("IdUser")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Id автора последнего изменения");
|
||||||
|
|
||||||
|
b.Property<object>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasComment("Значение уставки");
|
||||||
|
|
||||||
|
b.HasKey("Key", "Created");
|
||||||
|
|
||||||
|
b.ToTable("Setpoint");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Persistence.Database.Entity.DrillingSystem", "System")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SystemId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("System");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Persistence.Database.Postgres.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class TechMessageMigration : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "DrillingSystem",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
SystemId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id системы автобурения"),
|
||||||
|
Name = table.Column<string>(type: "varchar(256)", nullable: false, comment: "Наименование системы автобурения"),
|
||||||
|
Description = table.Column<string>(type: "text", nullable: true, comment: "Описание системы автобурения")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_DrillingSystem", x => x.SystemId);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "TechMessage",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
EventId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id события"),
|
||||||
|
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 системы автобурения, к которой относится сообщение"),
|
||||||
|
UserId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id пользователя за пультом бурильщика")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_TechMessage", x => x.EventId);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TechMessage_DrillingSystem_SystemId",
|
||||||
|
column: x => x.SystemId,
|
||||||
|
principalTable: "DrillingSystem",
|
||||||
|
principalColumn: "SystemId",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TechMessage_SystemId",
|
||||||
|
table: "TechMessage",
|
||||||
|
column: "SystemId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "TechMessage");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "DrillingSystem");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,89 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
|
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "adminpack");
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Entity.DrillingSystem", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("SystemId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Id системы автобурения");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasComment("Описание системы автобурения");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(256)")
|
||||||
|
.HasComment("Наименование системы автобурения");
|
||||||
|
|
||||||
|
b.HasKey("SystemId");
|
||||||
|
|
||||||
|
b.ToTable("DrillingSystem");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("EventId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Id события");
|
||||||
|
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("Id Категории важности");
|
||||||
|
|
||||||
|
b.Property<double?>("Depth")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasComment("Глубина забоя");
|
||||||
|
|
||||||
|
b.Property<string>("MessageText")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(512)")
|
||||||
|
.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 пользователя за пультом бурильщика");
|
||||||
|
|
||||||
|
b.HasKey("EventId");
|
||||||
|
|
||||||
|
b.HasIndex("SystemId");
|
||||||
|
|
||||||
|
b.ToTable("TechMessage");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Entity.TimestampedSet", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("IdDiscriminator")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Дискриминатор ссылка на тип сохраняемых данных");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Timestamp")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("Отметка времени, строго в UTC");
|
||||||
|
|
||||||
|
b.Property<string>("Set")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasComment("Набор сохраняемых данных");
|
||||||
|
|
||||||
|
b.HasKey("IdDiscriminator", "Timestamp");
|
||||||
|
|
||||||
|
b.ToTable("TimestampedSets", t =>
|
||||||
|
{
|
||||||
|
t.HasComment("Общая таблица данных временных рядов");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
|
modelBuilder.Entity("Persistence.Database.Model.DataSaub", b =>
|
||||||
{
|
{
|
||||||
b.Property<DateTimeOffset>("Date")
|
b.Property<DateTimeOffset>("Date")
|
||||||
@ -115,10 +198,10 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
|
|
||||||
b.Property<DateTimeOffset>("Created")
|
b.Property<DateTimeOffset>("Created")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasComment("Дата изменения уставки");
|
.HasComment("Дата создания уставки");
|
||||||
|
|
||||||
b.Property<int>("IdUser")
|
b.Property<Guid>("IdUser")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("uuid")
|
||||||
.HasComment("Id автора последнего изменения");
|
.HasComment("Id автора последнего изменения");
|
||||||
|
|
||||||
b.Property<object>("Value")
|
b.Property<object>("Value")
|
||||||
@ -130,6 +213,17 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
|
|
||||||
b.ToTable("Setpoint");
|
b.ToTable("Setpoint");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Persistence.Database.Entity.TechMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Persistence.Database.Entity.DrillingSystem", "System")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SystemId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("System");
|
||||||
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ public partial class PersistenceDbContext : DbContext
|
|||||||
|
|
||||||
public DbSet<Setpoint> Setpoint => Set<Setpoint>();
|
public DbSet<Setpoint> Setpoint => Set<Setpoint>();
|
||||||
|
|
||||||
|
public DbSet<TechMessage> TechMessage => Set<TechMessage>();
|
||||||
|
|
||||||
public DbSet<TimestampedSet> TimestampedSets => Set<TimestampedSet>();
|
public DbSet<TimestampedSet> TimestampedSets => Set<TimestampedSet>();
|
||||||
|
|
||||||
public PersistenceDbContext()
|
public PersistenceDbContext()
|
||||||
@ -40,5 +42,14 @@ public partial class PersistenceDbContext : DbContext
|
|||||||
modelBuilder.Entity<TimestampedSet>()
|
modelBuilder.Entity<TimestampedSet>()
|
||||||
.Property(e => e.Set)
|
.Property(e => e.Set)
|
||||||
.HasJsonConversion();
|
.HasJsonConversion();
|
||||||
|
|
||||||
|
modelBuilder.Entity<TechMessage>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasOne(t => t.System)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(t => t.SystemId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
Persistence.Database/Entity/DrillingSystem.cs
Normal file
16
Persistence.Database/Entity/DrillingSystem.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Persistence.Database.Entity;
|
||||||
|
public class DrillingSystem
|
||||||
|
{
|
||||||
|
[Key, Comment("Id системы автобурения")]
|
||||||
|
public Guid SystemId { get; set; }
|
||||||
|
|
||||||
|
[Required, Column(TypeName = "varchar(256)"), Comment("Наименование системы автобурения")]
|
||||||
|
public required string Name { get; set; }
|
||||||
|
|
||||||
|
[Comment("Описание системы автобурения")]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
}
|
@ -16,6 +16,6 @@ namespace Persistence.Database.Model
|
|||||||
public DateTimeOffset Created { get; set; }
|
public DateTimeOffset Created { get; set; }
|
||||||
|
|
||||||
[Comment("Id автора последнего изменения")]
|
[Comment("Id автора последнего изменения")]
|
||||||
public int IdUser { get; set; }
|
public Guid IdUser { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
Persistence.Database/Entity/TechMessage.cs
Normal file
33
Persistence.Database/Entity/TechMessage.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Persistence.Database.Entity
|
||||||
|
{
|
||||||
|
public class TechMessage
|
||||||
|
{
|
||||||
|
[Key, Comment("Id события")]
|
||||||
|
public Guid EventId { get; set; }
|
||||||
|
|
||||||
|
[Comment("Id Категории важности")]
|
||||||
|
public int CategoryId { get; set; }
|
||||||
|
|
||||||
|
[Comment("Дата возникновения")]
|
||||||
|
public DateTimeOffset Timestamp { get; set; }
|
||||||
|
|
||||||
|
[Comment("Глубина забоя")]
|
||||||
|
public double? Depth { get; set; }
|
||||||
|
|
||||||
|
[Column(TypeName = "varchar(512)"), Comment("Текст сообщения")]
|
||||||
|
public required string MessageText { get; set; }
|
||||||
|
|
||||||
|
[Required, Comment("Id системы автобурения, к которой относится сообщение")]
|
||||||
|
public required Guid SystemId { get; set; }
|
||||||
|
|
||||||
|
[Required, ForeignKey(nameof(SystemId)), Comment("Система автобурения, к которой относится сообщение")]
|
||||||
|
public virtual required DrillingSystem System { get; set; }
|
||||||
|
|
||||||
|
[Comment("Id пользователя за пультом бурильщика")]
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Mvc.TagHelpers.Cache;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Persistence.Client;
|
using Persistence.Client;
|
||||||
using Persistence.Client.Clients;
|
using Persistence.Client.Clients;
|
||||||
|
using Persistence.Database.Model;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Persistence.IntegrationTests.Controllers
|
namespace Persistence.IntegrationTests.Controllers
|
||||||
@ -46,7 +48,7 @@ namespace Persistence.IntegrationTests.Controllers
|
|||||||
public async Task GetCurrent_AfterSave_returns_success()
|
public async Task GetCurrent_AfterSave_returns_success()
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
var setpointKey = await Save();
|
var setpointKey = await Add();
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await setpointClient.GetCurrent([setpointKey]);
|
var response = await setpointClient.GetCurrent([setpointKey]);
|
||||||
@ -82,7 +84,7 @@ namespace Persistence.IntegrationTests.Controllers
|
|||||||
public async Task GetHistory_AfterSave_returns_success()
|
public async Task GetHistory_AfterSave_returns_success()
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
var setpointKey = await Save();
|
var setpointKey = await Add();
|
||||||
var historyMoment = DateTimeOffset.UtcNow;
|
var historyMoment = DateTimeOffset.UtcNow;
|
||||||
historyMoment = historyMoment.AddDays(1);
|
historyMoment = historyMoment.AddDays(1);
|
||||||
|
|
||||||
@ -119,7 +121,7 @@ namespace Persistence.IntegrationTests.Controllers
|
|||||||
public async Task GetLog_AfterSave_returns_success()
|
public async Task GetLog_AfterSave_returns_success()
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
var setpointKey = await Save();
|
var setpointKey = await Add();
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await setpointClient.GetLog([setpointKey]);
|
var response = await setpointClient.GetLog([setpointKey]);
|
||||||
@ -132,12 +134,92 @@ namespace Persistence.IntegrationTests.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Save_returns_success()
|
public async Task GetDatesRange_returns_success()
|
||||||
{
|
{
|
||||||
await Save();
|
//arrange
|
||||||
|
dbContext.CleanupDbSet<Setpoint>();
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await setpointClient.GetDatesRangeAsync(new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.Equal(DateTimeOffset.MinValue, response.Content!.From);
|
||||||
|
Assert.Equal(DateTimeOffset.MaxValue, response.Content!.To);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Guid> Save()
|
[Fact]
|
||||||
|
public async Task GetDatesRange_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
dbContext.CleanupDbSet<Setpoint>();
|
||||||
|
|
||||||
|
await Add();
|
||||||
|
|
||||||
|
var dateBegin = DateTimeOffset.MinValue;
|
||||||
|
var take = 1;
|
||||||
|
var part = await setpointClient.GetPart(dateBegin, take, new CancellationToken());
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await setpointClient.GetDatesRangeAsync(new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
|
||||||
|
var expectedValue = part.Content!
|
||||||
|
.FirstOrDefault()!.Created
|
||||||
|
.ToString("dd.MM.yyyy-HH:mm:ss");
|
||||||
|
var actualValueFrom = response.Content.From
|
||||||
|
.ToString("dd.MM.yyyy-HH:mm:ss");
|
||||||
|
Assert.Equal(expectedValue, actualValueFrom);
|
||||||
|
|
||||||
|
var actualValueTo = response.Content.To
|
||||||
|
.ToString("dd.MM.yyyy-HH:mm:ss");
|
||||||
|
Assert.Equal(expectedValue, actualValueTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPart_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dateBegin = DateTimeOffset.UtcNow;
|
||||||
|
var take = 2;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await setpointClient.GetPart(dateBegin, take, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.Empty(response.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPart_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dateBegin = DateTimeOffset.UtcNow;
|
||||||
|
var take = 1;
|
||||||
|
await Add();
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await setpointClient.GetPart(dateBegin, take, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.NotEmpty(response.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Save_returns_success()
|
||||||
|
{
|
||||||
|
await Add();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Guid> Add()
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
var setpointKey = Guid.NewGuid();
|
var setpointKey = Guid.NewGuid();
|
||||||
@ -148,10 +230,10 @@ namespace Persistence.IntegrationTests.Controllers
|
|||||||
};
|
};
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await setpointClient.Save(setpointKey, setpointValue);
|
var response = await setpointClient.Add(setpointKey, setpointValue);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||||
|
|
||||||
return setpointKey;
|
return setpointKey;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,288 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Persistence.Client;
|
||||||
|
using Persistence.Client.Clients;
|
||||||
|
using Persistence.Database.Entity;
|
||||||
|
using Persistence.Models;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Persistence.IntegrationTests.Controllers
|
||||||
|
{
|
||||||
|
public class TechMessagesControllerTest : BaseIntegrationTest
|
||||||
|
{
|
||||||
|
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey";
|
||||||
|
private readonly ITechMessagesClient techMessagesClient;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
|
public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
|
{
|
||||||
|
var scope = factory.Services.CreateScope();
|
||||||
|
var persistenceClientFactory = scope.ServiceProvider
|
||||||
|
.GetRequiredService<PersistenceClientFactory>();
|
||||||
|
|
||||||
|
techMessagesClient = persistenceClientFactory.GetClient<ITechMessagesClient>();
|
||||||
|
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPage_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
memoryCache.Remove(SystemCacheKey);
|
||||||
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
|
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||||
|
|
||||||
|
var requestDto = new RequestDto()
|
||||||
|
{
|
||||||
|
Skip = 1,
|
||||||
|
Take = 2,
|
||||||
|
SortSettings = nameof(TechMessage.CategoryId)
|
||||||
|
};
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetPage(requestDto, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.Empty(response.Content.Items);
|
||||||
|
Assert.Equal(requestDto.Skip, response.Content.Skip);
|
||||||
|
Assert.Equal(requestDto.Take, response.Content.Take);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPage_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dtos = await InsertRange();
|
||||||
|
var dtosCount = dtos.Count();
|
||||||
|
var requestDto = new RequestDto()
|
||||||
|
{
|
||||||
|
Skip = 0,
|
||||||
|
Take = 2,
|
||||||
|
SortSettings = nameof(TechMessage.CategoryId)
|
||||||
|
};
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetPage(requestDto, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.Equal(dtosCount, response.Content.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InsertRange_returns_success()
|
||||||
|
{
|
||||||
|
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.AddRange(dtos, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetSystems_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
memoryCache.Remove(SystemCacheKey);
|
||||||
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
|
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetSystems(new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.Empty(response.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetSystems_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dtos = await InsertRange();
|
||||||
|
var systems = dtos
|
||||||
|
.Select(e => e.System)
|
||||||
|
.Distinct()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetSystems(new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
string?[]? content = response.Content?.ToArray();
|
||||||
|
Assert.Equal(systems, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetStatistics_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
memoryCache.Remove(SystemCacheKey);
|
||||||
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
|
dbContext.CleanupDbSet<Database.Entity.DrillingSystem>();
|
||||||
|
|
||||||
|
var imortantId = 1;
|
||||||
|
var autoDrillingSystem = nameof(TechMessageDto.System);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.Empty(response.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetStatistics_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var imortantId = 0;
|
||||||
|
var autoDrillingSystem = nameof(TechMessageDto.System);
|
||||||
|
var dtos = await InsertRange();
|
||||||
|
var filteredDtos = dtos.Where(e => e.CategoryId == imortantId && e.System == autoDrillingSystem);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetStatistics(autoDrillingSystem, imortantId, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
var categories = response.Content
|
||||||
|
.FirstOrDefault()?.Categories
|
||||||
|
.FirstOrDefault(e => e.Key == 0).Value;
|
||||||
|
Assert.Equal(filteredDtos.Count(), categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetDatesRange_returns_success()
|
||||||
|
{
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
//Assert.Equal(DateTimeOffset.MinValue, response.Content?.From);
|
||||||
|
//Assert.Equal(DateTimeOffset.MaxValue, response.Content?.To);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetDatesRange_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
await InsertRange();
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetDatesRangeAsync(new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.NotNull(response.Content?.From);
|
||||||
|
Assert.NotNull(response.Content?.To);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPart_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dateBegin = DateTimeOffset.UtcNow;
|
||||||
|
var take = 2;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.Empty(response.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPart_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dateBegin = DateTimeOffset.UtcNow;
|
||||||
|
var take = 1;
|
||||||
|
await InsertRange();
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetPart(dateBegin, take, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.NotNull(response.Content);
|
||||||
|
Assert.NotEmpty(response.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<TechMessageDto>> InsertRange()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
memoryCache.Remove(SystemCacheKey);
|
||||||
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
|
dbContext.CleanupDbSet<DrillingSystem>();
|
||||||
|
|
||||||
|
var dtos = new List<TechMessageDto>()
|
||||||
|
{
|
||||||
|
new TechMessageDto()
|
||||||
|
{
|
||||||
|
EventId = Guid.NewGuid(),
|
||||||
|
CategoryId = 1,
|
||||||
|
Timestamp = DateTimeOffset.UtcNow,
|
||||||
|
Depth = 1.11,
|
||||||
|
MessageText = nameof(TechMessageDto.MessageText),
|
||||||
|
System = nameof(TechMessageDto.System).ToLower(),
|
||||||
|
UserId = Guid.NewGuid()
|
||||||
|
},
|
||||||
|
new TechMessageDto()
|
||||||
|
{
|
||||||
|
EventId = Guid.NewGuid(),
|
||||||
|
CategoryId = 2,
|
||||||
|
Timestamp = DateTimeOffset.UtcNow,
|
||||||
|
Depth = 2.22,
|
||||||
|
MessageText = nameof(TechMessageDto.MessageText),
|
||||||
|
System = nameof(TechMessageDto.System).ToLower(),
|
||||||
|
UserId = Guid.NewGuid()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.AddRange(dtos, new CancellationToken());
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||||
|
Assert.Equal(dtos.Count, response.Content);
|
||||||
|
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@ public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrat
|
|||||||
var expected = dto.Adapt<TDto>();
|
var expected = dto.Adapt<TDto>();
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await timeSeriesClient.InsertRange(new TDto[] { expected });
|
var response = await timeSeriesClient.AddRange(new TDto[] { expected });
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
@ -25,7 +25,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
IEnumerable<TimestampedSetDto> testSets = Generate(10, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(10, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var response = await client.InsertRange(idDiscriminator, testSets);
|
var response = await client.AddRange(idDiscriminator, testSets);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
|
||||||
@ -39,7 +39,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
Guid idDiscriminator = Guid.NewGuid();
|
Guid idDiscriminator = Guid.NewGuid();
|
||||||
int count = 10;
|
int count = 10;
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||||
var insertResponse = await client.InsertRange(idDiscriminator, testSets);
|
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var response = await client.Get(idDiscriminator, null, null, 0, int.MaxValue);
|
var response = await client.Get(idDiscriminator, null, null, 0, int.MaxValue);
|
||||||
@ -58,7 +58,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
Guid idDiscriminator = Guid.NewGuid();
|
Guid idDiscriminator = Guid.NewGuid();
|
||||||
int count = 10;
|
int count = 10;
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||||
var insertResponse = await client.InsertRange(idDiscriminator, testSets);
|
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||||
string[] props = ["A"];
|
string[] props = ["A"];
|
||||||
|
|
||||||
// act
|
// act
|
||||||
@ -86,7 +86,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
var dateMin = DateTimeOffset.Now;
|
var dateMin = DateTimeOffset.Now;
|
||||||
var dateMax = DateTimeOffset.Now.AddSeconds(count);
|
var dateMax = DateTimeOffset.Now.AddSeconds(count);
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
|
||||||
var insertResponse = await client.InsertRange(idDiscriminator, testSets);
|
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||||
var tail = testSets.OrderBy(t => t.Timestamp).Skip(count / 2).Take(int.MaxValue);
|
var tail = testSets.OrderBy(t => t.Timestamp).Skip(count / 2).Take(int.MaxValue);
|
||||||
var geDate = tail.First().Timestamp;
|
var geDate = tail.First().Timestamp;
|
||||||
var tolerance = TimeSpan.FromSeconds(1);
|
var tolerance = TimeSpan.FromSeconds(1);
|
||||||
@ -111,7 +111,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
Guid idDiscriminator = Guid.NewGuid();
|
Guid idDiscriminator = Guid.NewGuid();
|
||||||
int count = 10;
|
int count = 10;
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||||
var insertResponse = await client.InsertRange(idDiscriminator, testSets);
|
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||||
var expectedCount = count / 2;
|
var expectedCount = count / 2;
|
||||||
|
|
||||||
// act
|
// act
|
||||||
@ -133,7 +133,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
var expectedCount = 1;
|
var expectedCount = 1;
|
||||||
int count = 10 + expectedCount;
|
int count = 10 + expectedCount;
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||||
var insertResponse = await client.InsertRange(idDiscriminator, testSets);
|
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var response = await client.Get(idDiscriminator, null, null, count - expectedCount, count);
|
var response = await client.Get(idDiscriminator, null, null, count - expectedCount, count);
|
||||||
@ -152,7 +152,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
Guid idDiscriminator = Guid.NewGuid();
|
Guid idDiscriminator = Guid.NewGuid();
|
||||||
int count = 10;
|
int count = 10;
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||||
var insertResponse = await client.InsertRange(idDiscriminator, testSets);
|
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||||
var expectedCount = 8;
|
var expectedCount = 8;
|
||||||
|
|
||||||
// act
|
// act
|
||||||
@ -174,7 +174,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
var dateMin = DateTimeOffset.Now;
|
var dateMin = DateTimeOffset.Now;
|
||||||
var dateMax = DateTimeOffset.Now.AddSeconds(count-1);
|
var dateMax = DateTimeOffset.Now.AddSeconds(count-1);
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
|
||||||
var insertResponse = await client.InsertRange(idDiscriminator, testSets);
|
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||||
var tolerance = TimeSpan.FromSeconds(1);
|
var tolerance = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
@ -195,7 +195,7 @@ public class TimestampedSetControllerTest : BaseIntegrationTest
|
|||||||
Guid idDiscriminator = Guid.NewGuid();
|
Guid idDiscriminator = Guid.NewGuid();
|
||||||
int count = 144;
|
int count = 144;
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||||
var insertResponse = await client.InsertRange(idDiscriminator, testSets);
|
var insertResponse = await client.AddRange(idDiscriminator, testSets);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var response = await client.Count(idDiscriminator);
|
var response = await client.Count(idDiscriminator);
|
||||||
|
14
Persistence.IntegrationTests/Extensions/EFCoreExtensions.cs
Normal file
14
Persistence.IntegrationTests/Extensions/EFCoreExtensions.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using Persistence.Database.Model;
|
||||||
|
|
||||||
|
namespace Persistence.IntegrationTests.Extensions;
|
||||||
|
|
||||||
|
public static class EFCoreExtensions
|
||||||
|
{
|
||||||
|
public static void CleanupDbSet<T>(this PersistenceDbContext dbContext)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
var dbset = dbContext.Set<T>();
|
||||||
|
dbset.RemoveRange(dbset);
|
||||||
|
dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +0,0 @@
|
|||||||
namespace Persistence.Repository.Data
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Модель для работы с уставкой
|
|
||||||
/// </summary>
|
|
||||||
public class SetpointDto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Идентификатор уставки
|
|
||||||
/// </summary>
|
|
||||||
public int Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Значение уставки
|
|
||||||
/// </summary>
|
|
||||||
public required object Value { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Дата сохранения уставки
|
|
||||||
/// </summary>
|
|
||||||
public DateTimeOffset Edit { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ключ пользователя
|
|
||||||
/// </summary>
|
|
||||||
public int IdUser { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,6 +19,7 @@ public static class DependencyInjection
|
|||||||
services.AddTransient<ISetpointRepository, SetpointRepository>();
|
services.AddTransient<ISetpointRepository, SetpointRepository>();
|
||||||
services.AddTransient<ITimeSeriesDataRepository<DataSaubDto>, TimeSeriesDataCachedRepository<DataSaub, DataSaubDto>>();
|
services.AddTransient<ITimeSeriesDataRepository<DataSaubDto>, TimeSeriesDataCachedRepository<DataSaub, DataSaubDto>>();
|
||||||
services.AddTransient<ITimestampedSetRepository, TimestampedSetRepository>();
|
services.AddTransient<ITimestampedSetRepository, TimestampedSetRepository>();
|
||||||
|
services.AddTransient<ITechMessagesRepository, TechMessagesRepository>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
267
Persistence.Repository/Extensions/EFExtensionsSortBy.cs
Normal file
267
Persistence.Repository/Extensions/EFExtensionsSortBy.cs
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Persistence.Repository.Extensions;
|
||||||
|
|
||||||
|
public static class EFExtensionsSortBy
|
||||||
|
{
|
||||||
|
struct TypeAccessor
|
||||||
|
{
|
||||||
|
public LambdaExpression KeySelector { get; set; }
|
||||||
|
public MethodInfo OrderBy { get; set; }
|
||||||
|
public MethodInfo OrderByDescending { get; set; }
|
||||||
|
public MethodInfo ThenBy { get; set; }
|
||||||
|
public MethodInfo ThenByDescending { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ConcurrentDictionary<Type, Dictionary<string, TypeAccessor>> TypePropSelectors { get; set; } =
|
||||||
|
new();
|
||||||
|
|
||||||
|
private static readonly MethodInfo methodOrderBy = GetExtOrderMethod("OrderBy");
|
||||||
|
|
||||||
|
private static readonly MethodInfo methodOrderByDescending = GetExtOrderMethod("OrderByDescending");
|
||||||
|
|
||||||
|
private static readonly MethodInfo methodThenBy = GetExtOrderMethod("ThenBy");
|
||||||
|
|
||||||
|
private static readonly MethodInfo methodThenByDescending = GetExtOrderMethod("ThenByDescending");
|
||||||
|
|
||||||
|
private static MethodInfo GetExtOrderMethod(string methodName)
|
||||||
|
=> typeof(Queryable)
|
||||||
|
.GetMethods()
|
||||||
|
.Where(m => m.Name == methodName &&
|
||||||
|
m.IsGenericMethodDefinition &&
|
||||||
|
m.GetParameters().Length == 2 &&
|
||||||
|
m.GetParameters()[1].ParameterType.IsAssignableTo(typeof(LambdaExpression)))
|
||||||
|
.Single();
|
||||||
|
|
||||||
|
private static Dictionary<string, TypeAccessor> MakeTypeAccessors(Type type)
|
||||||
|
{
|
||||||
|
var propContainer = new Dictionary<string, TypeAccessor>();
|
||||||
|
var properties = type.GetProperties();
|
||||||
|
foreach (var propertyInfo in properties)
|
||||||
|
{
|
||||||
|
var name = propertyInfo.Name.ToLower();
|
||||||
|
ParameterExpression arg = Expression.Parameter(type, "x");
|
||||||
|
MemberExpression property = Expression.Property(arg, propertyInfo.Name);
|
||||||
|
var selector = Expression.Lambda(property, new ParameterExpression[] { arg });
|
||||||
|
var typeAccessor = new TypeAccessor
|
||||||
|
{
|
||||||
|
KeySelector = selector,
|
||||||
|
OrderBy = methodOrderBy.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||||
|
OrderByDescending = methodOrderByDescending.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||||
|
ThenBy = methodThenBy.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||||
|
ThenByDescending = methodThenByDescending.MakeGenericMethod(type, propertyInfo.PropertyType),
|
||||||
|
};
|
||||||
|
|
||||||
|
propContainer.Add(name, typeAccessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return propContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в запрос сортировку по возрастанию или убыванию.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource"></typeparam>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <param name="propertySort">
|
||||||
|
/// Свойство сортировки.
|
||||||
|
/// Состоит из названия свойства (в любом регистре)
|
||||||
|
/// и опционально указания направления сортировки "asc" или "desc"
|
||||||
|
/// </param>
|
||||||
|
/// <example>
|
||||||
|
/// var query = query("Date desc");
|
||||||
|
/// </example>
|
||||||
|
/// <returns>Запрос с примененной сортировкой</returns>
|
||||||
|
public static IOrderedQueryable<TSource> SortBy<TSource>(
|
||||||
|
this IQueryable<TSource> query,
|
||||||
|
IEnumerable<string> propertySorts)
|
||||||
|
{
|
||||||
|
if (propertySorts?.Any() != true)
|
||||||
|
return (IOrderedQueryable<TSource>)query;
|
||||||
|
|
||||||
|
var sortEnum = propertySorts.GetEnumerator();
|
||||||
|
sortEnum.MoveNext();
|
||||||
|
var orderedQuery = query.SortBy(sortEnum.Current);
|
||||||
|
|
||||||
|
while (sortEnum.MoveNext())
|
||||||
|
orderedQuery = orderedQuery.ThenSortBy(sortEnum.Current);
|
||||||
|
|
||||||
|
return orderedQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в запрос сортировку по возрастанию или убыванию.
|
||||||
|
/// Этот метод сбросит ранее наложенные сортировки.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource"></typeparam>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <param name="propertySort">
|
||||||
|
/// Свойство сортировки.
|
||||||
|
/// Состоит из названия свойства (в любом регистре)
|
||||||
|
/// и опционально указания направления сортировки "asc" или "desc"
|
||||||
|
/// </param>
|
||||||
|
/// <example>
|
||||||
|
/// var query = query("Date desc");
|
||||||
|
/// </example>
|
||||||
|
/// <returns>Запрос с примененной сортировкой</returns>
|
||||||
|
public static IOrderedQueryable<TSource> SortBy<TSource>(
|
||||||
|
this IQueryable<TSource> query,
|
||||||
|
string propertySort)
|
||||||
|
{
|
||||||
|
var parts = propertySort.Split(" ", 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var isDesc = parts.Length >= 2 && parts[1].ToLower().Trim() == "desc";
|
||||||
|
var propertyName = parts[0];
|
||||||
|
|
||||||
|
var newQuery = query.SortBy(propertyName, isDesc);
|
||||||
|
return newQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в запрос дополнительную сортировку по возрастанию или убыванию.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource"></typeparam>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <param name="propertySort">
|
||||||
|
/// Свойство сортировки.
|
||||||
|
/// Состоит из названия свойства (в любом регистре)
|
||||||
|
/// и опционально указания направления сортировки "asc" или "desc"
|
||||||
|
/// </param>
|
||||||
|
/// <example>
|
||||||
|
/// var query = query("Date desc");
|
||||||
|
/// </example>
|
||||||
|
/// <returns>Запрос с примененной сортировкой</returns>
|
||||||
|
public static IOrderedQueryable<TSource> ThenSortBy<TSource>(
|
||||||
|
this IOrderedQueryable<TSource> query,
|
||||||
|
string propertySort)
|
||||||
|
{
|
||||||
|
var parts = propertySort.Split(" ", 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var isDesc = parts.Length >= 2 && parts[1].ToLower().Trim() == "desc";
|
||||||
|
var propertyName = parts[0];
|
||||||
|
|
||||||
|
var newQuery = query.ThenSortBy(propertyName, isDesc);
|
||||||
|
return newQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в запрос сортировку по возрастанию или убыванию
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource"></typeparam>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <param name="propertyName">Название свойства (в любом регистре)</param>
|
||||||
|
/// <param name="isDesc">Сортировать по убыванию</param>
|
||||||
|
/// <returns>Запрос с примененной сортировкой</returns>
|
||||||
|
public static IOrderedQueryable<TSource> SortBy<TSource>(
|
||||||
|
this IQueryable<TSource> query,
|
||||||
|
string propertyName,
|
||||||
|
bool isDesc)
|
||||||
|
{
|
||||||
|
Type rootType = typeof(TSource);
|
||||||
|
var typePropSelector = TypePropSelectors.GetOrAdd(rootType, MakeTypeAccessors);
|
||||||
|
var propertyNameLower = propertyName.ToLower();
|
||||||
|
|
||||||
|
MethodInfo orderByDescending;
|
||||||
|
MethodInfo orderByAscending;
|
||||||
|
|
||||||
|
LambdaExpression? lambdaExpression = null;
|
||||||
|
|
||||||
|
if (propertyName.Contains('.'))
|
||||||
|
{
|
||||||
|
Type type = rootType;
|
||||||
|
ParameterExpression rootExpression = Expression.Parameter(rootType, "x");
|
||||||
|
Expression expr = rootExpression;
|
||||||
|
|
||||||
|
var propertyPath = propertyName.Split(".", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
for (int i = 0; i < propertyPath.Length; i++)
|
||||||
|
{
|
||||||
|
PropertyInfo pi = type.GetProperty(propertyPath[i])!;
|
||||||
|
expr = Expression.Property(expr, pi);
|
||||||
|
type = pi.PropertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type delegateType = typeof(Func<,>).MakeGenericType(rootType, type);
|
||||||
|
lambdaExpression = Expression.Lambda(delegateType, expr, rootExpression);
|
||||||
|
|
||||||
|
orderByAscending = methodOrderBy.MakeGenericMethod(rootType, type);
|
||||||
|
orderByDescending = methodOrderByDescending.MakeGenericMethod(rootType, type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var rootTypeAccessor = typePropSelector[propertyNameLower];
|
||||||
|
orderByAscending = rootTypeAccessor.OrderBy;
|
||||||
|
orderByDescending = rootTypeAccessor.OrderByDescending;
|
||||||
|
lambdaExpression = rootTypeAccessor.KeySelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
var genericMethod = isDesc
|
||||||
|
? orderByDescending
|
||||||
|
: orderByAscending;
|
||||||
|
|
||||||
|
var newQuery = (IOrderedQueryable<TSource>)genericMethod
|
||||||
|
.Invoke(genericMethod, new object[] { query, lambdaExpression })!;
|
||||||
|
return newQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить в запрос дополнительную сортировку по возрастанию или убыванию
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource"></typeparam>
|
||||||
|
/// <param name="query"></param>
|
||||||
|
/// <param name="propertyName">Название свойства (в любом регистре)</param>
|
||||||
|
/// <param name="isDesc">Сортировать по убыванию</param>
|
||||||
|
/// <returns>Запрос с примененной сортировкой</returns>
|
||||||
|
public static IOrderedQueryable<TSource> ThenSortBy<TSource>(
|
||||||
|
this IOrderedQueryable<TSource> query,
|
||||||
|
string propertyName,
|
||||||
|
bool isDesc)
|
||||||
|
{
|
||||||
|
Type rootType = typeof(TSource);
|
||||||
|
var typePropSelector = TypePropSelectors.GetOrAdd(rootType, MakeTypeAccessors);
|
||||||
|
var propertyNameLower = propertyName.ToLower();
|
||||||
|
|
||||||
|
MethodInfo orderByDescending;
|
||||||
|
MethodInfo orderByAscending;
|
||||||
|
|
||||||
|
LambdaExpression? lambdaExpression = null;
|
||||||
|
|
||||||
|
// TODO: Устранить дублирование кода
|
||||||
|
if (propertyName.Contains('.'))
|
||||||
|
{
|
||||||
|
Type type = rootType;
|
||||||
|
ParameterExpression rootExpression = Expression.Parameter(rootType, "x");
|
||||||
|
Expression expr = rootExpression;
|
||||||
|
|
||||||
|
var propertyPath = propertyName.Split(".", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
for (int i = 0; i < propertyPath.Length; i++)
|
||||||
|
{
|
||||||
|
PropertyInfo pi = type.GetProperty(propertyPath[i])!;
|
||||||
|
expr = Expression.Property(expr, pi);
|
||||||
|
type = pi.PropertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type delegateType = typeof(Func<,>).MakeGenericType(rootType, type);
|
||||||
|
lambdaExpression = Expression.Lambda(delegateType, expr, rootExpression);
|
||||||
|
|
||||||
|
orderByAscending = methodThenBy.MakeGenericMethod(rootType, type);
|
||||||
|
orderByDescending = methodThenByDescending.MakeGenericMethod(rootType, type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var rootTypeAccessor = typePropSelector[propertyNameLower];
|
||||||
|
orderByAscending = rootTypeAccessor.ThenBy;
|
||||||
|
orderByDescending = rootTypeAccessor.ThenByDescending;
|
||||||
|
lambdaExpression = rootTypeAccessor.KeySelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
var genericMethod = isDesc
|
||||||
|
? orderByDescending
|
||||||
|
: orderByAscending;
|
||||||
|
|
||||||
|
var newQuery = (IOrderedQueryable<TSource>)genericMethod
|
||||||
|
.Invoke(genericMethod, new object[] { query, lambdaExpression })!;
|
||||||
|
return newQuery;
|
||||||
|
}
|
||||||
|
}
|
@ -43,6 +43,38 @@ namespace Persistence.Repository.Repositories
|
|||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SetpointLogDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = GetQueryReadOnly();
|
||||||
|
var entities = await query
|
||||||
|
.Where(e => e.Created >= dateBegin)
|
||||||
|
.Take(take)
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
var dtos = entities
|
||||||
|
.Select(e => e.Adapt<SetpointLogDto>());
|
||||||
|
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = GetQueryReadOnly()
|
||||||
|
.GroupBy(e => 1)
|
||||||
|
.Select(group => new
|
||||||
|
{
|
||||||
|
Min = group.Min(e => e.Created),
|
||||||
|
Max = group.Max(e => e.Created),
|
||||||
|
});
|
||||||
|
var values = await query.FirstOrDefaultAsync(token);
|
||||||
|
var result = new DatesRangeDto()
|
||||||
|
{
|
||||||
|
From = values?.Min ?? DateTimeOffset.MinValue,
|
||||||
|
To = values?.Max ?? DateTimeOffset.MaxValue
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
public async Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||||
{
|
{
|
||||||
var query = GetQueryReadOnly();
|
var query = GetQueryReadOnly();
|
||||||
@ -56,7 +88,7 @@ namespace Persistence.Repository.Repositories
|
|||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Save(Guid setpointKey, object newValue, int idUser, CancellationToken token)
|
public async Task Add(Guid setpointKey, object newValue, Guid idUser, CancellationToken token)
|
||||||
{
|
{
|
||||||
var entity = new Setpoint()
|
var entity = new Setpoint()
|
||||||
{
|
{
|
||||||
|
177
Persistence.Repository/Repositories/TechMessagesRepository.cs
Normal file
177
Persistence.Repository/Repositories/TechMessagesRepository.cs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
using Mapster;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Persistence.Database.Entity;
|
||||||
|
using Persistence.Models;
|
||||||
|
using Persistence.Repositories;
|
||||||
|
using Persistence.Repository.Extensions;
|
||||||
|
|
||||||
|
namespace Persistence.Repository.Repositories
|
||||||
|
{
|
||||||
|
public class TechMessagesRepository : ITechMessagesRepository
|
||||||
|
{
|
||||||
|
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DrillingSystem).FullName}CacheKey";
|
||||||
|
private const int CacheExpirationInMinutes = 60;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
|
private DbContext db;
|
||||||
|
|
||||||
|
public TechMessagesRepository(DbContext db, IMemoryCache memoryCache)
|
||||||
|
{
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual IQueryable<TechMessage> GetQueryReadOnly() => db.Set<TechMessage>()
|
||||||
|
.Include(e => e.System);
|
||||||
|
|
||||||
|
public async Task<PaginationContainer<TechMessageDto>> GetPage(RequestDto request, CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = GetQueryReadOnly();
|
||||||
|
var count = await query.CountAsync(token);
|
||||||
|
|
||||||
|
var sort = request.SortSettings != string.Empty
|
||||||
|
? request.SortSettings
|
||||||
|
: nameof(TechMessage.Timestamp);
|
||||||
|
var entities = await query
|
||||||
|
.SortBy(request.SortSettings)
|
||||||
|
.Skip(request.Skip)
|
||||||
|
.Take(request.Take)
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
|
||||||
|
var dto = new PaginationContainer<TechMessageDto>()
|
||||||
|
{
|
||||||
|
Skip = request.Skip,
|
||||||
|
Take = request.Take,
|
||||||
|
Count = count,
|
||||||
|
Items = entities.Select(e => e.Adapt<TechMessageDto>())
|
||||||
|
};
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<MessagesStatisticDto>> GetStatistics(IEnumerable<string> autoDrillingSystem, IEnumerable<int> categoryIds, CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = GetQueryReadOnly();
|
||||||
|
var systems = autoDrillingSystem.Select(s => s.ToLower().Trim());
|
||||||
|
var result = await query
|
||||||
|
.Where(e => systems.Count() == 0 || systems.Contains(e.System.Name.ToLower().Trim()))
|
||||||
|
.GroupBy(e => e.System.Name, (key, group) => new
|
||||||
|
{
|
||||||
|
System = key,
|
||||||
|
Categories = group
|
||||||
|
.Where(g => categoryIds.Count() == 0 || categoryIds.Contains(g.CategoryId))
|
||||||
|
})
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
|
||||||
|
var entities = new List<MessagesStatisticDto>();
|
||||||
|
foreach (var e in result)
|
||||||
|
{
|
||||||
|
var categories = e.Categories
|
||||||
|
.GroupBy(g => g.CategoryId)
|
||||||
|
.ToDictionary(c => c.Key, v => v.Count());
|
||||||
|
var entity = new MessagesStatisticDto()
|
||||||
|
{
|
||||||
|
System = e.System,
|
||||||
|
Categories = categories
|
||||||
|
};
|
||||||
|
entities.Add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<string>> GetSystems(CancellationToken token)
|
||||||
|
{
|
||||||
|
var entities = await GetDrillingSystems(token);
|
||||||
|
var result = entities.Select(e => e.Name);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> AddRange(IEnumerable<TechMessageDto> dtos, Guid userId, CancellationToken token)
|
||||||
|
{
|
||||||
|
|
||||||
|
var entities = new List<TechMessage>();
|
||||||
|
foreach (var dto in dtos)
|
||||||
|
{
|
||||||
|
var entity = dto.Adapt<TechMessage>();
|
||||||
|
var systems = await GetDrillingSystems(token);
|
||||||
|
var systemId = systems.FirstOrDefault(e => e.Name.ToLower().Trim() == dto.System.ToLower().Trim())?.SystemId
|
||||||
|
?? await CreateDrillingSystem(dto.System, token);
|
||||||
|
|
||||||
|
entity.SystemId = systemId;
|
||||||
|
entity.UserId = userId;
|
||||||
|
|
||||||
|
entities.Add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.Set<TechMessage>().AddRangeAsync(entities, token);
|
||||||
|
var result = await db.SaveChangesAsync(token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TechMessageDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = GetQueryReadOnly();
|
||||||
|
var entities = await query
|
||||||
|
.Where(e => e.Timestamp >= dateBegin)
|
||||||
|
.Take(take)
|
||||||
|
.ToArrayAsync(token);
|
||||||
|
var dtos = entities
|
||||||
|
.Select(e => e.Adapt<TechMessageDto>());
|
||||||
|
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
var query = GetQueryReadOnly()
|
||||||
|
.GroupBy(e => 1)
|
||||||
|
.Select(group => new
|
||||||
|
{
|
||||||
|
Min = group.Min(e => e.Timestamp),
|
||||||
|
Max = group.Max(e => e.Timestamp),
|
||||||
|
});
|
||||||
|
var values = await query.FirstOrDefaultAsync(token);
|
||||||
|
var result = new DatesRangeDto()
|
||||||
|
{
|
||||||
|
From = values?.Min ?? DateTimeOffset.MinValue,
|
||||||
|
To = values?.Max ?? DateTimeOffset.MaxValue
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<Models.DrillingSystemDto>> GetDrillingSystems(CancellationToken token)
|
||||||
|
{
|
||||||
|
var systems = await memoryCache.GetOrCreateAsync(SystemCacheKey, async f =>
|
||||||
|
{
|
||||||
|
f.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CacheExpirationInMinutes);
|
||||||
|
|
||||||
|
var query = db.Set<Database.Entity.DrillingSystem>();
|
||||||
|
var entities = await query.ToListAsync(token);
|
||||||
|
var dtos = entities.Select(e => e.Adapt<Models.DrillingSystemDto>());
|
||||||
|
|
||||||
|
return dtos;
|
||||||
|
});
|
||||||
|
|
||||||
|
return systems!;
|
||||||
|
}
|
||||||
|
private async Task<Guid> CreateDrillingSystem(string name, CancellationToken token)
|
||||||
|
{
|
||||||
|
memoryCache.Remove(SystemCacheKey);
|
||||||
|
|
||||||
|
var entity = new Database.Entity.DrillingSystem()
|
||||||
|
{
|
||||||
|
SystemId = default,
|
||||||
|
Name = name.ToLower().Trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
await db.Set<Database.Entity.DrillingSystem>().AddAsync(entity);
|
||||||
|
await db.SaveChangesAsync(token);
|
||||||
|
|
||||||
|
return entity.SystemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,9 +48,9 @@ public class TimeSeriesDataCachedRepository<TEntity, TDto> : TimeSeriesDataRepos
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<int> InsertRange(IEnumerable<TDto> dtos, CancellationToken token)
|
public override async Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await base.InsertRange(dtos, token);
|
var result = await base.AddRange(dtos, token);
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ public class TimeSeriesDataRepository<TEntity, TDto> : ITimeSeriesDataRepository
|
|||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<int> InsertRange(IEnumerable<TDto> dtos, CancellationToken token)
|
public virtual async Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
{
|
{
|
||||||
var entities = dtos.Select(d => d.Adapt<TEntity>());
|
var entities = dtos.Select(d => d.Adapt<TEntity>());
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ public class TimestampedSetRepository : ITimestampedSetRepository
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<int> InsertRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token)
|
public Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token)
|
||||||
{
|
{
|
||||||
var entities = sets.Select(set => new TimestampedSet(idDiscriminator, set.Timestamp.ToUniversalTime(), set.Set));
|
var entities = sets.Select(set => new TimestampedSet(idDiscriminator, set.Timestamp.ToUniversalTime(), set.Set));
|
||||||
var dbSet = db.Set<TimestampedSet>();
|
var dbSet = db.Set<TimestampedSet>();
|
||||||
|
@ -6,7 +6,7 @@ namespace Persistence.API;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Интерфейс для API, предназначенного для работы с уставками
|
/// Интерфейс для API, предназначенного для работы с уставками
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISetpointApi
|
public interface ISetpointApi : ISyncApi<SetpointLogDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить актуальные значения уставок
|
/// Получить актуальные значения уставок
|
||||||
@ -40,5 +40,5 @@ public interface ISetpointApi
|
|||||||
/// <param name="newValue">значение</param>
|
/// <param name="newValue">значение</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ActionResult<int>> Save(Guid setpointKey, object newValue, CancellationToken token);
|
Task<IActionResult> Add(Guid setpointKey, object newValue, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace Persistence.API;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Интерфейс для API, предназначенного для синхронизации данных
|
/// Интерфейс для API, предназначенного для синхронизации данных
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISyncApi<TDto> where TDto : class, new()
|
public interface ISyncApi<TDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить порцию записей, начиная с заданной даты
|
/// Получить порцию записей, начиная с заданной даты
|
||||||
|
@ -28,7 +28,7 @@ public interface ITimeSeriesDataApi<TDto> : ITimeSeriesBaseDataApi<TDto>
|
|||||||
/// <param name="dtos"></param>
|
/// <param name="dtos"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IActionResult> InsertRange(IEnumerable<TDto> dtos, CancellationToken token);
|
Task<IActionResult> AddRange(IEnumerable<TDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
22
Persistence/Models/DrillingSystemDto.cs
Normal file
22
Persistence/Models/DrillingSystemDto.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace Persistence.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Модель системы автобурения
|
||||||
|
/// </summary>
|
||||||
|
public class DrillingSystemDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ключ
|
||||||
|
/// </summary>
|
||||||
|
public Guid SystemId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Наименование
|
||||||
|
/// </summary>
|
||||||
|
public required string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Описание
|
||||||
|
/// </summary>
|
||||||
|
public string? Description { get; set; }
|
||||||
|
}
|
17
Persistence/Models/MessagesStatisticDto.cs
Normal file
17
Persistence/Models/MessagesStatisticDto.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace Persistence.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Статистика сообщений по системам бурения
|
||||||
|
/// </summary>
|
||||||
|
public class MessagesStatisticDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Система бурения
|
||||||
|
/// </summary>
|
||||||
|
public required string System { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Количество сообщений в соответствии с категориями важности
|
||||||
|
/// </summary>
|
||||||
|
public required Dictionary<int, int> Categories { get; set; }
|
||||||
|
}
|
@ -13,5 +13,5 @@ public class SetpointLogDto : SetpointValueDto
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ключ пользователя
|
/// Ключ пользователя
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdUser { get; set; }
|
public Guid IdUser { get; set; }
|
||||||
}
|
}
|
||||||
|
52
Persistence/Models/TechMessageDto.cs
Normal file
52
Persistence/Models/TechMessageDto.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Persistence.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Модель технологического сообщения
|
||||||
|
/// </summary>
|
||||||
|
public class TechMessageDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id события
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public Guid EventId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id Категории важности
|
||||||
|
/// </summary>
|
||||||
|
[Range(0, int.MaxValue, ErrorMessage = "Id Категории важности не может быть меньше 0")]
|
||||||
|
public int CategoryId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата возникновения
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset Timestamp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя
|
||||||
|
/// </summary>
|
||||||
|
[Range(0, double.MaxValue, ErrorMessage = "Глубина забоя не может быть меньше 0")]
|
||||||
|
public double? Depth { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Текст сообщения
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
[StringLength(512, MinimumLength = 1, ErrorMessage = "Допустимая длина текста сообщения от 1 до 512 символов")]
|
||||||
|
public required string MessageText { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Система автобурения, к которой относится сообщение
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
[StringLength(256, MinimumLength = 1, ErrorMessage = "Допустимая длина наименования системы АБ от 1 до 256 символов")]
|
||||||
|
public required string System { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id пользователя за пультом бурильщика
|
||||||
|
/// </summary>
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -74,7 +74,7 @@ namespace Persistence.Repositories;
|
|||||||
// throw new NotImplementedException();
|
// throw new NotImplementedException();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// public async Task<int> InsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
// public async Task<int> AddRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
||||||
// {
|
// {
|
||||||
// using var transaction = dbContext.Database.BeginTransaction();
|
// using var transaction = dbContext.Database.BeginTransaction();
|
||||||
// try
|
// try
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Persistence.Models;
|
using Persistence.Models;
|
||||||
|
|
||||||
namespace Persistence.Repositories;
|
namespace Persistence.Repositories;
|
||||||
@ -32,6 +33,22 @@ public interface ISetpointRepository
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token);
|
Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить порцию записей, начиная с заданной даты
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateBegin"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<SetpointLogDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Метод сохранения уставки
|
/// Метод сохранения уставки
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -42,5 +59,5 @@ public interface ISetpointRepository
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// to do
|
/// to do
|
||||||
/// id User учесть в соответствующем методе репозитория
|
/// id User учесть в соответствующем методе репозитория
|
||||||
Task Save(Guid setpointKey, object newValue, int idUser, CancellationToken token);
|
Task Add(Guid setpointKey, object newValue, Guid idUser, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
59
Persistence/Repositories/ITechMessagesRepository.cs
Normal file
59
Persistence/Repositories/ITechMessagesRepository.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Persistence.Models;
|
||||||
|
|
||||||
|
namespace Persistence.Repositories
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Интерфейс по работе с технологическими сообщениями
|
||||||
|
/// </summary>
|
||||||
|
public interface ITechMessagesRepository
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Получить страницу списка объектов
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<PaginationContainer<TechMessageDto>> GetPage(RequestDto request, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавление новых сообщений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dtos"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> AddRange(IEnumerable<TechMessageDto> dtos, Guid userId, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение списка уникальных названий систем АБ
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<string>> GetSystems(CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение количества сообщений по категориям и системам автобурения
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="categoryId">Id Категории важности</param>
|
||||||
|
/// <param name="autoDrillingSystem">Система автобурения</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<MessagesStatisticDto>> GetStatistics(IEnumerable<string> autoDrillingSystem, IEnumerable<int> categoryIds, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить порцию записей, начиная с заданной даты
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateBegin"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<TechMessageDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token);
|
||||||
|
}
|
||||||
|
}
|
@ -15,5 +15,5 @@ public interface ITimeSeriesDataRepository<TDto> : ISyncRepository<TDto>, ITimeS
|
|||||||
/// <param name="dtos"></param>
|
/// <param name="dtos"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<int> InsertRange(IEnumerable<TDto> dtos, CancellationToken token);
|
Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
@ -55,5 +55,5 @@ public interface ITimestampedSetRepository
|
|||||||
/// <param name="sets"></param>
|
/// <param name="sets"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<int> InsertRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token);
|
Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user