Merge branch 'master' into Partitioning
All checks were successful
Unit tests / test (push) Successful in 2m23s
All checks were successful
Unit tests / test (push) Successful in 2m23s
This commit is contained in:
commit
b09d2dd704
@ -4,6 +4,7 @@ using DD.Persistence.Models;
|
|||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
using DD.Persistence.Repositories;
|
using DD.Persistence.Repositories;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.API.Controllers;
|
namespace DD.Persistence.API.Controllers;
|
||||||
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using DD.Persistence.Models;
|
|
||||||
using DD.Persistence.Repositories;
|
|
||||||
|
|
||||||
namespace DD.Persistence.API.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Работа с временными данными
|
|
||||||
/// </summary>
|
|
||||||
[ApiController]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
public class DataSaubController : TimeSeriesController<DataSaubDto>
|
|
||||||
{
|
|
||||||
public DataSaubController(ITimeSeriesDataRepository<DataSaubDto> timeSeriesDataRepository) : base(timeSeriesDataRepository)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,6 +3,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
using DD.Persistence.Repositories;
|
using DD.Persistence.Repositories;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Text.Json;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.API.Controllers;
|
namespace DD.Persistence.API.Controllers;
|
||||||
|
|
||||||
@ -28,9 +30,9 @@ public class SetpointController : ControllerBase, ISetpointApi
|
|||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpGet("current")]
|
[HttpGet("current")]
|
||||||
public async Task<ActionResult<IEnumerable<SetpointValueDto>>> GetCurrent([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
public async Task<ActionResult<Dictionary<Guid, object>>> GetCurrent([FromQuery] IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await setpointRepository.GetCurrent(setpointKeys, token);
|
var result = await setpointRepository.GetCurrentDictionary(setpointKeys, token);
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
@ -104,7 +106,7 @@ public class SetpointController : ControllerBase, ISetpointApi
|
|||||||
public async Task<IActionResult> Add(Guid setpointKey, object newValue, CancellationToken token)
|
public async Task<IActionResult> Add(Guid setpointKey, object newValue, CancellationToken token)
|
||||||
{
|
{
|
||||||
var userId = User.GetUserId<Guid>();
|
var userId = User.GetUserId<Guid>();
|
||||||
await setpointRepository.Add(setpointKey, newValue, userId, token);
|
await setpointRepository.Add(setpointKey, (JsonElement)newValue, userId, token);
|
||||||
|
|
||||||
return CreatedAtAction(nameof(Add), true);
|
return CreatedAtAction(nameof(Add), true);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using DD.Persistence.Models;
|
|||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
using DD.Persistence.Repositories;
|
using DD.Persistence.Repositories;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.API.Controllers;
|
namespace DD.Persistence.API.Controllers;
|
||||||
|
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using DD.Persistence.Models;
|
|
||||||
using DD.Persistence.Repositories;
|
|
||||||
|
|
||||||
namespace DD.Persistence.API.Controllers;
|
|
||||||
|
|
||||||
[ApiController]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
public class TimeSeriesController<TDto> : ControllerBase, ITimeSeriesDataApi<TDto>
|
|
||||||
where TDto : class, ITimeSeriesAbstractDto, new()
|
|
||||||
{
|
|
||||||
private readonly ITimeSeriesDataRepository<TDto> timeSeriesDataRepository;
|
|
||||||
|
|
||||||
public TimeSeriesController(ITimeSeriesDataRepository<TDto> timeSeriesDataRepository)
|
|
||||||
{
|
|
||||||
this.timeSeriesDataRepository = timeSeriesDataRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить список объектов, удовлетворяющий диапазону дат
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dateBegin"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
public async Task<IActionResult> Get(DateTimeOffset dateBegin, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await timeSeriesDataRepository.GetGtDate(dateBegin, token);
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить диапазон дат, для которых есть данные в репозитории
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet("datesRange")]
|
|
||||||
public async Task<IActionResult> GetDatesRange(CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await timeSeriesDataRepository.GetDatesRange(token);
|
|
||||||
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")]
|
|
||||||
public async Task<IActionResult> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
var result = await timeSeriesDataRepository.GetResampledData(dateBegin, intervalSec, approxPointsCount, token);
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Добавить записи
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dtos"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IActionResult> AddRange(IEnumerable<TDto> dtos, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await timeSeriesDataRepository.AddRange(dtos, token);
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,104 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using DD.Persistence.Models;
|
|
||||||
using DD.Persistence.Repositories;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace DD.Persistence.API.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Хранение наборов данных с отметкой времени.
|
|
||||||
/// Не оптимизировано под большие данные.
|
|
||||||
/// </summary>
|
|
||||||
[ApiController]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/[controller]/{idDiscriminator}")]
|
|
||||||
public class TimestampedSetController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ITimestampedSetRepository repository;
|
|
||||||
|
|
||||||
public TimestampedSetController(ITimestampedSetRepository repository)
|
|
||||||
{
|
|
||||||
this.repository = repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Записать новые данные
|
|
||||||
/// Предполагается что данные с одним дискриминатором имеют одинаковую структуру
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator">Дискриминатор (идентификатор) набора</param>
|
|
||||||
/// <param name="sets"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns>кол-во затронутых записей</returns>
|
|
||||||
[HttpPost]
|
|
||||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
|
||||||
public async Task<IActionResult> AddRange([FromRoute] Guid idDiscriminator, [FromBody] IEnumerable<TimestampedSetDto> sets, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await repository.AddRange(idDiscriminator, sets, token);
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получение данных с фильтрацией. Значение фильтра null - отключен
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator">Дискриминатор (идентификатор) набора</param>
|
|
||||||
/// <param name="geTimestamp">Фильтр позднее даты</param>
|
|
||||||
/// <param name="columnNames">Фильтр свойств набора. Можно запросить только некоторые свойства из набора</param>
|
|
||||||
/// <param name="skip"></param>
|
|
||||||
/// <param name="take"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns>Фильтрованный набор данных с сортировкой по отметке времени</returns>
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(typeof(IEnumerable<TimestampedSetDto>), (int)HttpStatusCode.OK)]
|
|
||||||
public async Task<IActionResult> Get(Guid idDiscriminator, DateTimeOffset? geTimestamp, [FromQuery] IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await repository.Get(idDiscriminator, geTimestamp, columnNames, skip, take, token);
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить последние данные
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator">Дискриминатор (идентификатор) набора</param>
|
|
||||||
/// <param name="columnNames">Фильтр свойств набора. Можно запросить только некоторые свойства из набора</param>
|
|
||||||
/// <param name="take"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns>Фильтрованный набор данных с сортировкой по отметке времени</returns>
|
|
||||||
[HttpGet("last")]
|
|
||||||
[ProducesResponseType(typeof(IEnumerable<TimestampedSetDto>), (int)HttpStatusCode.OK)]
|
|
||||||
public async Task<IActionResult> GetLast(Guid idDiscriminator, [FromQuery] IEnumerable<string>? columnNames, int take, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await repository.GetLast(idDiscriminator, columnNames, take, token);
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Диапазон дат за которые есть данные
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns>Дата первой и последней записи</returns>
|
|
||||||
[HttpGet("datesRange")]
|
|
||||||
[ProducesResponseType(typeof(DatesRangeDto), (int)HttpStatusCode.OK)]
|
|
||||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
|
||||||
public async Task<IActionResult> GetDatesRange(Guid idDiscriminator, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await repository.GetDatesRange(idDiscriminator, token);
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Количество записей по указанному набору в БД. Для пагинации.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator">Дискриминатор (идентификатор) набора</param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet("count")]
|
|
||||||
[ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
|
|
||||||
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
|
||||||
public async Task<IActionResult> Count(Guid idDiscriminator, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await repository.Count(idDiscriminator, token);
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
151
DD.Persistence.API/Controllers/TimestampedValuesController.cs
Normal file
151
DD.Persistence.API/Controllers/TimestampedValuesController.cs
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
using DD.Persistence.Services.Interfaces;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace DD.Persistence.API.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Хранение наборов данных с отметкой времени.
|
||||||
|
/// </summary>
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
[Route("api/[controller]/{discriminatorId}")]
|
||||||
|
public class TimestampedValuesController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ITimestampedValuesService timestampedValuesRepository;
|
||||||
|
|
||||||
|
public TimestampedValuesController(ITimestampedValuesService repository)
|
||||||
|
{
|
||||||
|
this.timestampedValuesRepository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Записать новые данные.
|
||||||
|
/// Предполагается что данные с одним дискриминатором имеют одинаковую структуру
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="dtos"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
[HttpPost]
|
||||||
|
[ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
|
||||||
|
public async Task<IActionResult> AddRange([FromRoute] Guid discriminatorId, [FromBody] IEnumerable<TimestampedValuesDto> dtos, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await timestampedValuesRepository.AddRange(discriminatorId, dtos, token);
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(AddRange), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение данных с фильтрацией. Значение фильтра null - отключен
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="timestampBegin">Фильтр позднее даты</param>
|
||||||
|
/// <param name="columnNames">Фильтр свойств набора</param>
|
||||||
|
/// <param name="skip"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
[HttpGet]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||||
|
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||||
|
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> Get([FromRoute] Guid discriminatorId, DateTimeOffset? timestampBegin, [FromQuery] string[]? columnNames, int skip, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await timestampedValuesRepository.Get(discriminatorId, timestampBegin, columnNames, skip, take, token);
|
||||||
|
|
||||||
|
return result.Any() ? Ok(result) : NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные, начиная с заданной отметки времени
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="timestampBegin">Фильтр позднее даты</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
[HttpGet("gtdate")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||||
|
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||||
|
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> GetGtDate([FromRoute] Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await timestampedValuesRepository.GetGtDate(discriminatorId, timestampBegin, token);
|
||||||
|
|
||||||
|
return result.Any() ? Ok(result) : NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные c начала
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
[HttpGet("first")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||||
|
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||||
|
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> GetFirst([FromRoute] Guid discriminatorId, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await timestampedValuesRepository.GetFirst(discriminatorId, take, token);
|
||||||
|
|
||||||
|
return result.Any() ? Ok(result) : NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные c конца
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
[HttpGet("last")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||||
|
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||||
|
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> GetLast([FromRoute] Guid discriminatorId, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await timestampedValuesRepository.GetLast(discriminatorId, take, token);
|
||||||
|
|
||||||
|
return result.Any() ? Ok(result) : NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить список объектов с прореживанием, удовлетворяющий диапазону дат
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="timestampBegin">Фильтр позднее даты</param>
|
||||||
|
/// <param name="intervalSec"></param>
|
||||||
|
/// <param name="approxPointsCount"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
[HttpGet("resampled")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<TimestampedValuesDto>), (int)HttpStatusCode.OK)]
|
||||||
|
[ProducesResponseType((int)HttpStatusCode.NoContent)]
|
||||||
|
public async Task<ActionResult<IEnumerable<TimestampedValuesDto>>> GetResampledData([FromRoute] Guid discriminatorId, DateTimeOffset timestampBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
var result = await timestampedValuesRepository.GetResampledData(discriminatorId, timestampBegin, intervalSec, approxPointsCount, token);
|
||||||
|
|
||||||
|
return result.Any() ? Ok(result) : NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить количество записей по указанному набору в БД. Для пагинации
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
[HttpGet("count")]
|
||||||
|
public async Task<ActionResult<int>> Count([FromRoute] Guid discriminatorId, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await timestampedValuesRepository.Count(discriminatorId, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить диапазон дат, в пределах которых хранятся даные
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
[HttpGet("datesRange")]
|
||||||
|
public async Task<ActionResult<DatesRangeDto>> GetDatesRange([FromRoute] Guid discriminatorId, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await timestampedValuesRepository.GetDatesRange(discriminatorId, token);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
using DD.Persistence.Services.Interfaces;
|
using DD.Persistence.Services.Interfaces;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.API.Controllers;
|
namespace DD.Persistence.API.Controllers;
|
||||||
|
|
||||||
|
@ -16,12 +16,6 @@ namespace DD.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 =>
|
||||||
@ -59,6 +53,7 @@ public static class DependencyInjection
|
|||||||
public static void AddServices(this IServiceCollection services)
|
public static void AddServices(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddTransient<IWitsDataService, WitsDataService>();
|
services.AddTransient<IWitsDataService, WitsDataService>();
|
||||||
|
services.AddTransient<ITimestampedValuesService, TimestampedValuesService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Authentication
|
#region Authentication
|
||||||
|
51
DD.Persistence.API/Readme.md
Normal file
51
DD.Persistence.API/Readme.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Persistence Service Readme
|
||||||
|
|
||||||
|
## Краткое описание
|
||||||
|
Persistence сервис отвечает за работу с хранимыми данными
|
||||||
|
в рамках совокупности различных систем.
|
||||||
|
|
||||||
|
## Локальное развертывание
|
||||||
|
1. Скачать репозиторий по SSH
|
||||||
|
```
|
||||||
|
ssh://git@git.ddrilling.ru:2221/on.nemtina/persistence.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Для доступа к репозиториям редварительно необходимо сгенерировать SSH ключ и добавить его в Gitea
|
||||||
|
|
||||||
|
2. Выбрать ветку dev
|
||||||
|
|
||||||
|
## Использование Swagger-а
|
||||||
|
1. Сконфигурировать appsettings.Development.json
|
||||||
|
(при отсутствии) занести флаг:
|
||||||
|
```json
|
||||||
|
"NeedUseKeyCloak": true
|
||||||
|
```
|
||||||
|
2. Запустить решение в режиме Debug
|
||||||
|
3. Выполнить авторизацию через KeyCloak - качестве client_id указать:
|
||||||
|
```
|
||||||
|
webapi
|
||||||
|
```
|
||||||
|
После этого должен произойти редирект на страницу авторизации в KeyCloak
|
||||||
|
|
||||||
|
4. Заполнить поля и авторизоваться
|
||||||
|
```
|
||||||
|
Username or email: myuser
|
||||||
|
```
|
||||||
|
```
|
||||||
|
Password: 12345
|
||||||
|
```
|
||||||
|
|
||||||
|
## Тестирование
|
||||||
|
Запуск тестов рекомендуется осуществлять без использования KeyCloak<br> Для этого
|
||||||
|
настройка appsettings.Tests.json должна содержать:
|
||||||
|
```
|
||||||
|
"NeedUseKeyCloak": false,
|
||||||
|
"AuthUser": {
|
||||||
|
"username": "myuser",
|
||||||
|
"password": 12345,
|
||||||
|
"clientId": "webapi",
|
||||||
|
"grantType": "password"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
@ -26,8 +26,6 @@ public class Startup
|
|||||||
services.AddJWTAuthentication(Configuration);
|
services.AddJWTAuthentication(Configuration);
|
||||||
services.AddMemoryCache();
|
services.AddMemoryCache();
|
||||||
services.AddServices();
|
services.AddServices();
|
||||||
|
|
||||||
//DependencyInjection.MapsterSetup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"password": 12345,
|
"password": 12345,
|
||||||
"clientId": "webapi",
|
"clientId": "webapi",
|
||||||
"grantType": "password",
|
"grantType": "password",
|
||||||
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "7d9f3574-6574-4ca3-845a-0276eb4aa8f6"
|
"http://schemas.xmlsoap.org/ws/2005/05/identity /claims/nameidentifier": "7d9f3574-6574-4ca3-845a-0276eb4aa8f6"
|
||||||
}
|
},
|
||||||
|
"ClientUrl": "http://localhost:5000/"
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,18 @@ using DD.Persistence.Client.Clients.Base;
|
|||||||
using DD.Persistence.Client.Clients.Interfaces;
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients;
|
namespace DD.Persistence.Client.Clients;
|
||||||
public class ChangeLogClient : BaseClient, IChangeLogClient
|
public class ChangeLogClient : BaseClient, IChangeLogClient
|
||||||
{
|
{
|
||||||
private readonly Interfaces.Refit.IRefitChangeLogClient refitChangeLogClient;
|
private readonly IRefitChangeLogClient refitChangeLogClient;
|
||||||
|
|
||||||
public ChangeLogClient(Interfaces.Refit.IRefitChangeLogClient refitChangeLogClient, ILogger<ChangeLogClient> logger) : base(logger)
|
public ChangeLogClient(IRefitClientFactory<IRefitChangeLogClient> refitClientFactory, ILogger<ChangeLogClient> logger) : base(logger)
|
||||||
{
|
{
|
||||||
this.refitChangeLogClient = refitChangeLogClient;
|
this.refitChangeLogClient = refitClientFactory.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
public async Task<int> ClearAndAddRange(Guid idDiscriminator, IEnumerable<DataWithWellDepthAndSectionDto> dtos, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
@ -9,9 +9,9 @@ public class DataSourceSystemClient : BaseClient, IDataSourceSystemClient
|
|||||||
{
|
{
|
||||||
private readonly IRefitDataSourceSystemClient dataSourceSystemClient;
|
private readonly IRefitDataSourceSystemClient dataSourceSystemClient;
|
||||||
|
|
||||||
public DataSourceSystemClient(IRefitDataSourceSystemClient dataSourceSystemClient, ILogger<DataSourceSystemClient> logger) : base(logger)
|
public DataSourceSystemClient(IRefitClientFactory<IRefitDataSourceSystemClient> dataSourceSystemClientFactory, ILogger<DataSourceSystemClient> logger) : base(logger)
|
||||||
{
|
{
|
||||||
this.dataSourceSystemClient = dataSourceSystemClient;
|
this.dataSourceSystemClient = dataSourceSystemClientFactory.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token)
|
public async Task Add(DataSourceSystemDto dataSourceSystemDto, CancellationToken token)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces;
|
namespace DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces;
|
namespace DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
|
||||||
@ -24,12 +25,21 @@ public interface ISetpointClient : IDisposable
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token);
|
Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить диапазон дат, для которых есть данные в репозитории
|
/// Получить актуальные значения уставок
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token"></param>
|
/// <param name="setpointConfigs"></param>
|
||||||
/// <returns></returns>
|
/// <param name="token"></param>
|
||||||
Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token);
|
/// <returns></returns>s
|
||||||
|
Task<Dictionary<Guid, object>> GetCurrentDictionary(IEnumerable<Guid> setpointConfigs, CancellationToken token);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить диапазон дат, для которых есть данные в репозитории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить значения уставок за определенный момент времени
|
/// Получить значения уставок за определенный момент времени
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces;
|
namespace DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
using DD.Persistence.Models;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Клиент для работы с временными данными
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TDto"></typeparam>
|
|
||||||
public interface ITimeSeriesClient<TDto> : IDisposable where TDto : class, new()
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Добавление записей
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dtos"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить список объектов, удовлетворяющий диапазону дат
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dateBegin"></param>
|
|
||||||
/// <param name="dateEnd"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<IEnumerable<TDto>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить диапазон дат, для которых есть данные в репозитории
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<DatesRangeDto?> GetDatesRange(CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить список объектов с прореживанием, удовлетворяющий диапазону дат
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dateBegin"></param>
|
|
||||||
/// <param name="intervalSec"></param>
|
|
||||||
/// <param name="approxPointsCount"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<IEnumerable<TDto>> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default);
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
using DD.Persistence.Models;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Клиент для работы с репозиторием для хранения разных наборов данных рядов.
|
|
||||||
/// idDiscriminator - идентифицирует конкретный набор данных, прим.: циклы измерения АСИБР, или отчет о DrillTest.
|
|
||||||
/// idDiscriminator формируют клиенты и только им известно что они обозначают.
|
|
||||||
/// Так как данные приходят редко, то их прореживания для построения графиков не предусмотрено.
|
|
||||||
/// </summary>
|
|
||||||
public interface ITimestampedSetClient : IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Записать новые данные
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator"></param>
|
|
||||||
/// <param name="sets"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Количество записей по указанному набору в БД. Для пагинации
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<int> Count(Guid idDiscriminator, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получение данных с фильтрацией. Значение фильтра null - отключен
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator"></param>
|
|
||||||
/// <param name="geTimestamp"></param>
|
|
||||||
/// <param name="columnNames"></param>
|
|
||||||
/// <param name="skip"></param>
|
|
||||||
/// <param name="take"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<IEnumerable<TimestampedSetDto>> Get(Guid idDiscriminator, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Диапазон дат за которые есть данные
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idDiscriminator"></param>
|
|
||||||
/// <param name="columnNames"></param>
|
|
||||||
/// <param name="take"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<IEnumerable<TimestampedSetDto>> GetLast(Guid idDiscriminator, IEnumerable<string>? columnNames, int take, CancellationToken token);
|
|
||||||
}
|
|
@ -0,0 +1,103 @@
|
|||||||
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Клиент для работы с наборами данных, имеющими отметку времени.
|
||||||
|
/// discriminatorId - идентифицирует конкретный набор данных, прим.: циклы измерения АСИБР, или отчет о DrillTest.
|
||||||
|
/// discriminatorId формируют клиенты и только им известно что они обозначают.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITimestampedValuesClient : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Записать новые данные
|
||||||
|
/// Предполагается что данные с одним дискриминатором имеют одинаковую структуру
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="dtos"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные с фильтрацией. Значение фильтра null - отключен
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="timestampBegin">Фильтр позднее даты</param>
|
||||||
|
/// <param name="columnNames">Фильтр свойств набора</param>
|
||||||
|
/// <param name="skip"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<IEnumerable<TimestampedValuesDto>> Get(Guid discriminatorId, DateTimeOffset? timestampBegin, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные, начиная с заданной отметки времени
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="timestampBegin">Фильтр позднее даты</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<IEnumerable<TimestampedValuesDto>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные с начала
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<IEnumerable<TimestampedValuesDto>> GetFirst(Guid discriminatorId, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные с конца
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<IEnumerable<TimestampedValuesDto>> GetLast(Guid discriminatorId, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные с прореживанием, удовлетворяющем диапазону дат
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="timestampBegin"></param>
|
||||||
|
/// <param name="intervalSec"></param>
|
||||||
|
/// <param name="approxPointsCount"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<IEnumerable<TimestampedValuesDto>> GetResampledData(Guid discriminatorId, DateTimeOffset timestampBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Количество записей по указанному набору в БД. Для пагинации
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<int> Count(Guid discriminatorId, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Диапазон дат, в пределах которых осуществляется хранение данных
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<DatesRangeDto?> GetDatesRange(Guid discriminatorId, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="idDiscriminator"></param>
|
||||||
|
/// <param name="geTimestamp"></param>
|
||||||
|
/// <param name="columnNames"></param>
|
||||||
|
/// <param name="skip"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<T>> Get<T>(Guid idDiscriminator, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="idDiscriminator"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<T>> GetLast<T>(Guid idDiscriminator, int take, CancellationToken token);
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
using Refit;
|
using Refit;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces;
|
namespace DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
using Refit;
|
using Refit;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
|
||||||
public interface IRefitChangeLogClient : IDisposable
|
public interface IRefitChangeLogClient : IRefitClient, IDisposable
|
||||||
{
|
{
|
||||||
private const string BaseRoute = "/api/ChangeLog";
|
private const string BaseRoute = "/api/ChangeLog";
|
||||||
|
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Базовый Refit интерфейс
|
||||||
|
/// </summary>
|
||||||
|
public interface IRefitClient
|
||||||
|
{
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
using Refit;
|
using Refit;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
public interface IRefitDataSourceSystemClient : IDisposable
|
public interface IRefitDataSourceSystemClient : IRefitClient, IDisposable
|
||||||
{
|
{
|
||||||
private const string BaseRoute = "/api/dataSourceSystem";
|
private const string BaseRoute = "/api/dataSourceSystem";
|
||||||
|
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
using Refit;
|
using Refit;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
|
||||||
public interface IRefitSetpointClient : IDisposable
|
public interface IRefitSetpointClient : IRefitClient, IDisposable
|
||||||
{
|
{
|
||||||
private const string BaseRoute = "/api/setpoint";
|
private const string BaseRoute = "/api/setpoint";
|
||||||
|
|
||||||
|
//[Get($"{BaseRoute}/current")]
|
||||||
|
//Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, CancellationToken token);
|
||||||
|
|
||||||
[Get($"{BaseRoute}/current")]
|
[Get($"{BaseRoute}/current")]
|
||||||
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, CancellationToken token);
|
Task<IApiResponse<Dictionary<Guid, JsonElement>>> GetCurrent([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, CancellationToken token);
|
||||||
|
|
||||||
[Get($"{BaseRoute}/history")]
|
[Get($"{BaseRoute}/history")]
|
||||||
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetHistory([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, [Query] DateTimeOffset historyMoment, CancellationToken token);
|
Task<IApiResponse<IEnumerable<SetpointValueDto>>> GetHistory([Query(CollectionFormat.Multi)] IEnumerable<Guid> setpointKeys, [Query] DateTimeOffset historyMoment, CancellationToken token);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using DD.Persistence.Models;
|
||||||
using DD.Persistence.Models;
|
|
||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
using Refit;
|
using Refit;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces.Refit
|
namespace DD.Persistence.Client.Clients.Interfaces.Refit
|
||||||
{
|
{
|
||||||
public interface IRefitTechMessagesClient : IDisposable
|
public interface IRefitTechMessagesClient : IRefitClient, IDisposable
|
||||||
{
|
{
|
||||||
private const string BaseRoute = "/api/techMessages";
|
private const string BaseRoute = "/api/techMessages";
|
||||||
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
using DD.Persistence.Models;
|
|
||||||
using Refit;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
|
||||||
public interface IRefitTimeSeriesClient<TDto> : IDisposable
|
|
||||||
where TDto : class, new()
|
|
||||||
{
|
|
||||||
private const string BaseRoute = "/api/dataSaub";
|
|
||||||
|
|
||||||
[Post($"{BaseRoute}")]
|
|
||||||
Task<IApiResponse<int>> AddRange(IEnumerable<TDto> dtos, CancellationToken token);
|
|
||||||
|
|
||||||
[Get($"{BaseRoute}")]
|
|
||||||
Task<IApiResponse<IEnumerable<TDto>>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token);
|
|
||||||
|
|
||||||
[Get($"{BaseRoute}/resampled")]
|
|
||||||
Task<IApiResponse<IEnumerable<TDto>>> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default);
|
|
||||||
|
|
||||||
[Get($"{BaseRoute}/datesRange")]
|
|
||||||
Task<IApiResponse<DatesRangeDto?>> GetDatesRange(CancellationToken token);
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
using DD.Persistence.Models;
|
|
||||||
using Refit;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
|
||||||
|
|
||||||
public interface IRefitTimestampedSetClient : IDisposable
|
|
||||||
{
|
|
||||||
private const string baseUrl = "/api/TimestampedSet/{idDiscriminator}";
|
|
||||||
|
|
||||||
[Post(baseUrl)]
|
|
||||||
Task<IApiResponse<int>> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token);
|
|
||||||
|
|
||||||
[Get(baseUrl)]
|
|
||||||
Task<IApiResponse<IEnumerable<TimestampedSetDto>>> Get(Guid idDiscriminator, [Query] DateTimeOffset? geTimestamp, [Query] IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
|
||||||
|
|
||||||
[Get($"{baseUrl}/last")]
|
|
||||||
Task<IApiResponse<IEnumerable<TimestampedSetDto>>> GetLast(Guid idDiscriminator, [Query] IEnumerable<string>? columnNames, int take, CancellationToken token);
|
|
||||||
|
|
||||||
[Get($"{baseUrl}/count")]
|
|
||||||
Task<IApiResponse<int>> Count(Guid idDiscriminator, CancellationToken token);
|
|
||||||
|
|
||||||
[Get($"{baseUrl}/datesRange")]
|
|
||||||
Task<IApiResponse<DatesRangeDto?>> GetDatesRange(Guid idDiscriminator, CancellationToken token);
|
|
||||||
}
|
|
@ -0,0 +1,61 @@
|
|||||||
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
using Refit;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Refit интерфейс для TimestampedValuesController
|
||||||
|
/// </summary>
|
||||||
|
public interface IRefitTimestampedValuesClient : IRefitClient, IDisposable
|
||||||
|
{
|
||||||
|
private const string baseUrl = "/api/TimestampedValues/{discriminatorId}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Записать новые данные
|
||||||
|
/// </summary>
|
||||||
|
[Post(baseUrl)]
|
||||||
|
Task<IApiResponse<int>> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение данных с фильтрацией
|
||||||
|
/// </summary>
|
||||||
|
[Get(baseUrl)]
|
||||||
|
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> Get(Guid discriminatorId, DateTimeOffset? timestampBegin, [Query(CollectionFormat.Multi)] IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные, начиная с заданной отметки времени
|
||||||
|
/// </summary>
|
||||||
|
[Get($"{baseUrl}/gtdate")]
|
||||||
|
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные c начала
|
||||||
|
/// </summary>
|
||||||
|
[Get($"{baseUrl}/first")]
|
||||||
|
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> GetFirst(Guid discriminatorId, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные c конца
|
||||||
|
/// </summary>
|
||||||
|
[Get($"{baseUrl}/last")]
|
||||||
|
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> GetLast(Guid discriminatorId, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить список объектов с прореживанием, удовлетворяющий диапазону временных отметок
|
||||||
|
/// </summary>
|
||||||
|
[Get($"{baseUrl}/resampled")]
|
||||||
|
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> GetResampledData(Guid discriminatorId, DateTimeOffset timestampBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить количество записей по указанному набору в БД. Для пагинации
|
||||||
|
/// </summary>
|
||||||
|
[Get($"{baseUrl}/count")]
|
||||||
|
Task<IApiResponse<int>> Count(Guid discriminatorId, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить диапазон дат, в пределах которых хранятся даные
|
||||||
|
/// </summary>
|
||||||
|
[Get($"{baseUrl}/datesRange")]
|
||||||
|
Task<IApiResponse<DatesRangeDto?>> GetDatesRange(Guid discriminatorId, CancellationToken token);
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using DD.Persistence.Models;
|
||||||
using DD.Persistence.Models;
|
|
||||||
using Refit;
|
using Refit;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
namespace DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
public interface IRefitWitsDataClient : IDisposable
|
public interface IRefitWitsDataClient : IRefitClient, IDisposable
|
||||||
{
|
{
|
||||||
private const string BaseRoute = "/api/witsData";
|
private const string BaseRoute = "/api/witsData";
|
||||||
|
|
||||||
|
@ -1,33 +1,60 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using DD.Persistence.Client.Clients.Base;
|
using DD.Persistence.Client.Clients.Base;
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Globalization;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients;
|
namespace DD.Persistence.Client.Clients;
|
||||||
|
|
||||||
public class SetpointClient : BaseClient, ISetpointClient
|
public class SetpointClient : BaseClient, ISetpointClient
|
||||||
{
|
{
|
||||||
private readonly IRefitSetpointClient refitSetpointClient;
|
private readonly IRefitSetpointClient refitSetpointClient;
|
||||||
|
private readonly ISetpointConfigStorage setpointConfigStorage;
|
||||||
|
|
||||||
public SetpointClient(IRefitSetpointClient refitSetpointClient, ILogger<SetpointClient> logger) : base(logger)
|
public SetpointClient(
|
||||||
|
IRefitClientFactory<IRefitSetpointClient> refitSetpointClientFactory,
|
||||||
|
ISetpointConfigStorage setpointConfigStorage,
|
||||||
|
ILogger<SetpointClient> logger) : base(logger)
|
||||||
{
|
{
|
||||||
this.refitSetpointClient = refitSetpointClient;
|
this.refitSetpointClient = refitSetpointClientFactory.Create();
|
||||||
}
|
this.setpointConfigStorage = setpointConfigStorage;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await ExecuteGetResponse(
|
var result = await ExecuteGetResponse(
|
||||||
async () => await refitSetpointClient.GetCurrent(setpointKeys, token), token);
|
async () => await refitSetpointClient.GetCurrent(setpointKeys, token), token);
|
||||||
|
|
||||||
return result!;
|
return result!.Select(x => new SetpointValueDto {
|
||||||
|
Key = x.Key,
|
||||||
|
Value = DeserializeValue(x.Key, x.Value)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
|
|
||||||
|
|
||||||
|
public async Task<Dictionary<Guid, object>> GetCurrentDictionary(IEnumerable<Guid> setpointConfigs, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await ExecuteGetResponse(
|
||||||
|
async () => await refitSetpointClient.GetCurrent(setpointConfigs, token), token);
|
||||||
|
|
||||||
|
|
||||||
|
return result!.ToDictionary(x => x.Key,x => DeserializeValue(x.Key,x.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await ExecuteGetResponse(
|
var result = await ExecuteGetResponse(
|
||||||
async () => await refitSetpointClient.GetHistory(setpointKeys, historyMoment, token), token);
|
async () => await refitSetpointClient.GetHistory(setpointKeys, historyMoment, token), token);
|
||||||
|
|
||||||
|
foreach(var dto in result)
|
||||||
|
dto.Value = DeserializeValue(dto.Key, (JsonElement)dto.Value);
|
||||||
|
|
||||||
|
|
||||||
return result!;
|
return result!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,6 +63,9 @@ public class SetpointClient : BaseClient, ISetpointClient
|
|||||||
var result = await ExecuteGetResponse(
|
var result = await ExecuteGetResponse(
|
||||||
async () => await refitSetpointClient.GetLog(setpointKeys, token), token);
|
async () => await refitSetpointClient.GetLog(setpointKeys, token), token);
|
||||||
|
|
||||||
|
foreach(var item in result)
|
||||||
|
DeserializeList(result[item.Key]);
|
||||||
|
|
||||||
return result!;
|
return result!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,14 +78,18 @@ public class SetpointClient : BaseClient, ISetpointClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SetpointLogDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
public async Task<IEnumerable<SetpointLogDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||||
{
|
{
|
||||||
var result = await ExecuteGetResponse(
|
var result = await ExecuteGetResponse(
|
||||||
async () => await refitSetpointClient.GetPart(dateBegin, take, token), token);
|
async () => await refitSetpointClient.GetPart(dateBegin, take, token), token);
|
||||||
|
|
||||||
return result!;
|
DeserializeList(result);
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Add(Guid setpointKey, object newValue, CancellationToken token)
|
return result!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async Task Add(Guid setpointKey, object newValue, CancellationToken token)
|
||||||
{
|
{
|
||||||
await ExecutePostResponse(
|
await ExecutePostResponse(
|
||||||
async () => await refitSetpointClient.Add(setpointKey, newValue, token), token);
|
async () => await refitSetpointClient.Add(setpointKey, newValue, token), token);
|
||||||
@ -67,4 +101,21 @@ public class SetpointClient : BaseClient, ISetpointClient
|
|||||||
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private object DeserializeValue(Guid key, JsonElement value)
|
||||||
|
{
|
||||||
|
if (setpointConfigStorage.TryGetType(key, out var type))
|
||||||
|
return value.Deserialize(type)!;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
private void DeserializeList(IEnumerable<SetpointLogDto>? result)
|
||||||
|
{
|
||||||
|
foreach (var log in result)
|
||||||
|
log.Value = DeserializeValue(log.Key, (JsonElement)log.Value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using DD.Persistence.Client.Clients.Interfaces;
|
|||||||
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients;
|
namespace DD.Persistence.Client.Clients;
|
||||||
|
|
||||||
@ -11,9 +12,9 @@ public class TechMessagesClient : BaseClient, ITechMessagesClient
|
|||||||
{
|
{
|
||||||
private readonly IRefitTechMessagesClient refitTechMessagesClient;
|
private readonly IRefitTechMessagesClient refitTechMessagesClient;
|
||||||
|
|
||||||
public TechMessagesClient(IRefitTechMessagesClient refitTechMessagesClient, ILogger<TechMessagesClient> logger) : base(logger)
|
public TechMessagesClient(IRefitClientFactory<IRefitTechMessagesClient> refitTechMessagesClientFactory, ILogger<TechMessagesClient> logger) : base(logger)
|
||||||
{
|
{
|
||||||
this.refitTechMessagesClient = refitTechMessagesClient;
|
this.refitTechMessagesClient = refitTechMessagesClientFactory.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PaginationContainer<TechMessageDto>> GetPage(PaginationRequest request, CancellationToken token)
|
public async Task<PaginationContainer<TechMessageDto>> GetPage(PaginationRequest request, CancellationToken token)
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using DD.Persistence.Client.Clients.Base;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
|
||||||
using DD.Persistence.Models;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients;
|
|
||||||
public class TimeSeriesClient<TDto> : BaseClient, ITimeSeriesClient<TDto> where TDto : class, new()
|
|
||||||
{
|
|
||||||
private readonly IRefitTimeSeriesClient<TDto> timeSeriesClient;
|
|
||||||
|
|
||||||
public TimeSeriesClient(IRefitTimeSeriesClient<TDto> refitTechMessagesClient, ILogger<TimeSeriesClient<TDto>> logger) : base(logger)
|
|
||||||
{
|
|
||||||
this.timeSeriesClient = refitTechMessagesClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> AddRange(IEnumerable<TDto> dtos, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await ExecutePostResponse(
|
|
||||||
async () => await timeSeriesClient.AddRange(dtos, token), token);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<TDto>> Get(DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await ExecuteGetResponse(
|
|
||||||
async () => await timeSeriesClient.Get(dateBegin, dateEnd, token), token);
|
|
||||||
|
|
||||||
return result!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<TDto>> GetResampledData(DateTimeOffset dateBegin, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
var result = await ExecuteGetResponse(
|
|
||||||
async () => await timeSeriesClient.GetResampledData(dateBegin, intervalSec, approxPointsCount, token), token);
|
|
||||||
|
|
||||||
return result!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<DatesRangeDto?> GetDatesRange(CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await ExecuteGetResponse(
|
|
||||||
async () => await timeSeriesClient.GetDatesRange(token), token);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
timeSeriesClient.Dispose();
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using DD.Persistence.Client.Clients.Base;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
|
||||||
using DD.Persistence.Models;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients;
|
|
||||||
public class TimestampedSetClient : BaseClient, ITimestampedSetClient
|
|
||||||
{
|
|
||||||
private readonly IRefitTimestampedSetClient refitTimestampedSetClient;
|
|
||||||
|
|
||||||
public TimestampedSetClient(IRefitTimestampedSetClient refitTimestampedSetClient, ILogger<TimestampedSetClient> logger) : base(logger)
|
|
||||||
{
|
|
||||||
this.refitTimestampedSetClient = refitTimestampedSetClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> AddRange(Guid idDiscriminator, IEnumerable<TimestampedSetDto> sets, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await ExecutePostResponse(
|
|
||||||
async () => await refitTimestampedSetClient.AddRange(idDiscriminator, sets, token), token);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<TimestampedSetDto>> Get(Guid idDiscriminator, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await ExecuteGetResponse(
|
|
||||||
async () => await refitTimestampedSetClient.Get(idDiscriminator, geTimestamp, columnNames, skip, take, token), token);
|
|
||||||
|
|
||||||
return result!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<TimestampedSetDto>> GetLast(Guid idDiscriminator, IEnumerable<string>? columnNames, int take, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await ExecuteGetResponse(
|
|
||||||
async () => await refitTimestampedSetClient.GetLast(idDiscriminator, columnNames, take, token), token);
|
|
||||||
|
|
||||||
return result!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> Count(Guid idDiscriminator, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await ExecuteGetResponse(
|
|
||||||
async () => await refitTimestampedSetClient.Count(idDiscriminator, token), token);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<DatesRangeDto?> GetDatesRange(Guid idDiscriminator, CancellationToken token)
|
|
||||||
{
|
|
||||||
var result = await ExecuteGetResponse(
|
|
||||||
async () => await refitTimestampedSetClient.GetDatesRange(idDiscriminator, token), token);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
refitTimestampedSetClient.Dispose();
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
127
DD.Persistence.Client/Clients/TimestampedValuesClient.cs
Normal file
127
DD.Persistence.Client/Clients/TimestampedValuesClient.cs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Base;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
||||||
|
{
|
||||||
|
private readonly IRefitTimestampedValuesClient refitTimestampedSetClient;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TimestampedValuesClient(IRefitClientFactory<IRefitTimestampedValuesClient> refitTimestampedSetClientFactory, ILogger<TimestampedValuesClient> logger) : base(logger)
|
||||||
|
{
|
||||||
|
this.refitTimestampedSetClient = refitTimestampedSetClientFactory.Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
private readonly ConcurrentDictionary<Guid, TimestampedSetMapperBase> mapperCache = new();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> sets, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await ExecutePostResponse(
|
||||||
|
async () => await refitTimestampedSetClient.AddRange(discriminatorId, sets, token), token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> Get(Guid discriminatorId, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await ExecuteGetResponse(
|
||||||
|
async () => await refitTimestampedSetClient.Get(discriminatorId, geTimestamp, columnNames, skip, take, token), token);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await ExecuteGetResponse(
|
||||||
|
async () => await refitTimestampedSetClient.GetGtDate(discriminatorId, timestampBegin, token), token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> GetFirst(Guid discriminatorId, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await ExecuteGetResponse(
|
||||||
|
async () => await refitTimestampedSetClient.GetFirst(discriminatorId, take, token), token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> GetLast(Guid discriminatorId, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await ExecuteGetResponse(
|
||||||
|
async () => await refitTimestampedSetClient.GetLast(discriminatorId, take, token), token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> GetResampledData(Guid discriminatorId, DateTimeOffset dateBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
var result = await ExecuteGetResponse(
|
||||||
|
async () => await refitTimestampedSetClient.GetResampledData(discriminatorId, dateBegin, intervalSec, approxPointsCount, token), token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<int> Count(Guid discriminatorId, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await ExecuteGetResponse(
|
||||||
|
async () => await refitTimestampedSetClient.Count(discriminatorId, token), token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<DatesRangeDto?> GetDatesRange(Guid discriminatorId, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await ExecuteGetResponse(
|
||||||
|
async () => await refitTimestampedSetClient.GetDatesRange(discriminatorId, token), token);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<T>> Get<T>(Guid idDiscriminator, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var data = await Get(idDiscriminator, geTimestamp, columnNames, skip, take, token);
|
||||||
|
var mapper = GetMapper<T>(idDiscriminator);
|
||||||
|
|
||||||
|
return data.Select(mapper.DeserializeTimeStampedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<T>> GetLast<T>(Guid idDiscriminator, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var data = await GetLast(idDiscriminator, take, token);
|
||||||
|
var mapper = GetMapper<T>(idDiscriminator);
|
||||||
|
|
||||||
|
return data.Select(mapper.DeserializeTimeStampedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
private TimestampedSetMapper<T> GetMapper<T>(Guid idDiscriminator)
|
||||||
|
{
|
||||||
|
return (TimestampedSetMapper<T>)mapperCache.GetOrAdd(idDiscriminator, name => new TimestampedSetMapper<T>(idDiscriminator));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
refitTimestampedSetClient.Dispose();
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
@ -3,15 +3,16 @@ using DD.Persistence.Client.Clients.Base;
|
|||||||
using DD.Persistence.Client.Clients.Interfaces;
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients;
|
namespace DD.Persistence.Client.Clients;
|
||||||
public class WitsDataClient : BaseClient, IWitsDataClient
|
public class WitsDataClient : BaseClient, IWitsDataClient
|
||||||
{
|
{
|
||||||
private readonly IRefitWitsDataClient refitWitsDataClient;
|
private readonly IRefitWitsDataClient refitWitsDataClient;
|
||||||
|
|
||||||
public WitsDataClient(IRefitWitsDataClient refitWitsDataClient, ILogger<WitsDataClient> logger) : base(logger)
|
public WitsDataClient(IRefitClientFactory<IRefitWitsDataClient> refitWitsDataClientFactory, ILogger<WitsDataClient> logger) : base(logger)
|
||||||
{
|
{
|
||||||
this.refitWitsDataClient = refitWitsDataClient;
|
this.refitWitsDataClient = refitWitsDataClientFactory.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> AddRange(IEnumerable<WitsDataDto> dtos, CancellationToken token)
|
public async Task<int> AddRange(IEnumerable<WitsDataDto> dtos, CancellationToken token)
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
<!--Генерация NuGet пакета при сборке-->
|
<!--Генерация NuGet пакета при сборке-->
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<!--Наименование-->
|
<!--Наименование-->
|
||||||
<Title>Persistence.Client</Title>
|
<Title>DD.Persistence.Client</Title>
|
||||||
<!--Версия пакета-->
|
<!--Версия пакета-->
|
||||||
<VersionPrefix>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
|
<VersionPrefix>1.5.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1</VersionPrefix>
|
||||||
<!--Версия сборки-->
|
<!--Версия сборки-->
|
||||||
<AssemblyVersion>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
|
<AssemblyVersion>1.5.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH)).1</AssemblyVersion>
|
||||||
<!--Id пакета-->
|
<!--Id пакета-->
|
||||||
<PackageId>Persistence.Client</PackageId>
|
<PackageId>DD.Persistence.Client</PackageId>
|
||||||
|
|
||||||
<!--Автор-->
|
<!--Автор-->
|
||||||
<Authors>Digital Drilling</Authors>
|
<Authors>Digital Drilling</Authors>
|
||||||
@ -33,15 +33,15 @@
|
|||||||
<!--Формат пакета с символами-->
|
<!--Формат пакета с символами-->
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
<!--Путь к пакету-->
|
<!--Путь к пакету-->
|
||||||
<PackageOutputPath>C:\Projects\Nuget</PackageOutputPath>
|
<PackageOutputPath>C:\Projects\Nuget\Persistence</PackageOutputPath>
|
||||||
|
|
||||||
<!--Readme-->
|
<!--Readme-->
|
||||||
<PackageReadmeFile>Readme.md</PackageReadmeFile>
|
<PackageReadmeFile>Readme.md</PackageReadmeFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VersionPrefix>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
|
<VersionPrefix>1.5.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
|
||||||
<AssemblyVersion>1.0.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
|
<AssemblyVersion>1.5.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -53,11 +53,12 @@
|
|||||||
<PackageReference Include="Refit" Version="8.0.0" />
|
<PackageReference Include="Refit" Version="8.0.0" />
|
||||||
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
|
<PackageReference Include="Refit.HttpClientFactory" Version="8.0.0" />
|
||||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||||
|
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\DD.Persistence\DD.Persistence.csproj" />
|
<ProjectReference Include="..\DD.Persistence.Models\DD.Persistence.Models.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
34
DD.Persistence.Client/DependencyInjection.cs
Normal file
34
DD.Persistence.Client/DependencyInjection.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using DD.Persistence.Client.Clients;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Models;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public static class DependencyInjection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IServiceCollection AddPersistenceClients(this IServiceCollection services, Dictionary<Guid, Type>? setpointTypeConfigs = null)
|
||||||
|
{
|
||||||
|
services.AddTransient(typeof(IRefitClientFactory<>), typeof(RefitClientFactory<>));
|
||||||
|
services.AddTransient<IChangeLogClient, ChangeLogClient>();
|
||||||
|
services.AddTransient<IDataSourceSystemClient, DataSourceSystemClient>();
|
||||||
|
services.AddTransient<ISetpointClient, SetpointClient>();
|
||||||
|
services.AddTransient<ITechMessagesClient, TechMessagesClient>();
|
||||||
|
services.AddTransient<ITimestampedValuesClient, TimestampedValuesClient>();
|
||||||
|
services.AddTransient<IWitsDataClient, WitsDataClient>();
|
||||||
|
|
||||||
|
services.AddSingleton<ISetpointConfigStorage, SetpointConfigStorage>(provider =>
|
||||||
|
{
|
||||||
|
return new SetpointConfigStorage(setpointTypeConfigs);
|
||||||
|
});
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
16
DD.Persistence.Client/IRefitClientFactory.cs
Normal file
16
DD.Persistence.Client/IRefitClientFactory.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Интерфейс для фабрики, которая создает refit-клиентов
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public interface IRefitClientFactory<T> where T : IRefitClient
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Создание refit-клиента
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public T Create();
|
||||||
|
}
|
11
DD.Persistence.Client/ISetpointConfigStorage.cs
Normal file
11
DD.Persistence.Client/ISetpointConfigStorage.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client;
|
||||||
|
public interface ISetpointConfigStorage
|
||||||
|
{
|
||||||
|
bool TryGetType(Guid id, out Type type);
|
||||||
|
}
|
@ -1,146 +0,0 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
|
||||||
using DD.Persistence.Client.Clients;
|
|
||||||
using DD.Persistence.Client.Helpers;
|
|
||||||
using Refit;
|
|
||||||
using DD.Persistence.Factories;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Client
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Фабрика клиентов для доступа к Persistence - сервису
|
|
||||||
/// </summary>
|
|
||||||
public class PersistenceClientFactory
|
|
||||||
{
|
|
||||||
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
|
|
||||||
{
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
PropertyNameCaseInsensitive = true
|
|
||||||
};
|
|
||||||
private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
|
|
||||||
private readonly IServiceProvider provider;
|
|
||||||
private HttpClient httpClient;
|
|
||||||
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IServiceProvider provider, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
this.provider = provider;
|
|
||||||
|
|
||||||
httpClient = httpClientFactory.CreateClient();
|
|
||||||
|
|
||||||
httpClient.Authorize(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PersistenceClientFactory(IHttpClientFactory httpClientFactory, IAuthTokenFactory authTokenFactory, IServiceProvider provider, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
this.provider = provider;
|
|
||||||
|
|
||||||
httpClient = httpClientFactory.CreateClient();
|
|
||||||
|
|
||||||
var token = authTokenFactory.GetToken();
|
|
||||||
httpClient.Authorize(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить клиент для работы с уставками
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ISetpointClient GetSetpointClient()
|
|
||||||
{
|
|
||||||
var logger = provider.GetRequiredService<ILogger<SetpointClient>>();
|
|
||||||
|
|
||||||
var restClient = RestService.For<IRefitSetpointClient>(httpClient, RefitSettings);
|
|
||||||
var client = new SetpointClient(restClient, logger);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить клиент для работы с технологическими сообщениями
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ITechMessagesClient GetTechMessagesClient()
|
|
||||||
{
|
|
||||||
var logger = provider.GetRequiredService<ILogger<TechMessagesClient>>();
|
|
||||||
|
|
||||||
var restClient = RestService.For<IRefitTechMessagesClient>(httpClient, RefitSettings);
|
|
||||||
var client = new TechMessagesClient(restClient, logger);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить клиент для работы с временными данными
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TDto"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ITimeSeriesClient<TDto> GetTimeSeriesClient<TDto>()
|
|
||||||
where TDto : class, new()
|
|
||||||
{
|
|
||||||
var logger = provider.GetRequiredService<ILogger<TimeSeriesClient<TDto>>>();
|
|
||||||
|
|
||||||
var restClient = RestService.For<IRefitTimeSeriesClient<TDto>>(httpClient, RefitSettings);
|
|
||||||
var client = new TimeSeriesClient<TDto>(restClient, logger);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить клиент для работы с данными с отметкой времени
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ITimestampedSetClient GetTimestampedSetClient()
|
|
||||||
{
|
|
||||||
var logger = provider.GetRequiredService<ILogger<TimestampedSetClient>>();
|
|
||||||
|
|
||||||
var restClient = RestService.For<IRefitTimestampedSetClient>(httpClient, RefitSettings);
|
|
||||||
var client = new TimestampedSetClient(restClient, logger);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить клиент для работы с записями ChangeLog
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IChangeLogClient GetChangeLogClient()
|
|
||||||
{
|
|
||||||
var logger = provider.GetRequiredService<ILogger<ChangeLogClient>>();
|
|
||||||
|
|
||||||
var restClient = RestService.For<IRefitChangeLogClient>(httpClient, RefitSettings);
|
|
||||||
var client = new ChangeLogClient(restClient, logger);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить клиент для работы c параметрами Wits
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IWitsDataClient GetWitsDataClient()
|
|
||||||
{
|
|
||||||
var logger = provider.GetRequiredService<ILogger<WitsDataClient>>();
|
|
||||||
|
|
||||||
var restClient = RestService.For<IRefitWitsDataClient>(httpClient, RefitSettings);
|
|
||||||
var client = new WitsDataClient(restClient, logger);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить клиент для работы c системами
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IDataSourceSystemClient GetDataSourceSystemClient()
|
|
||||||
{
|
|
||||||
var logger = provider.GetRequiredService<ILogger<DataSourceSystemClient>>();
|
|
||||||
|
|
||||||
var restClient = RestService.For<IRefitDataSourceSystemClient>(httpClient, RefitSettings);
|
|
||||||
var client = new DataSourceSystemClient(restClient, logger);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,8 +11,7 @@ Persistence сервисом посредством обращения к кон
|
|||||||
## Список предоставляемых клиентов
|
## Список предоставляемых клиентов
|
||||||
- `ISetpointClient` - Клиент для работы с уставками
|
- `ISetpointClient` - Клиент для работы с уставками
|
||||||
- `ITechMessagesClient` - Клиент для работы с технологическими сообщениями
|
- `ITechMessagesClient` - Клиент для работы с технологическими сообщениями
|
||||||
- `ITimeSeriesClient` - Клиент для работы с временными данными
|
- `ITimestampedValuesClient` - Клиент для работы с наборами данных, имеющими отметку времени
|
||||||
- `ITimestampedSetClient` - Клиент для работы с данными с отметкой времени
|
|
||||||
- `IChangeLogClient` - Клиент для работы с записями ChangeLog
|
- `IChangeLogClient` - Клиент для работы с записями ChangeLog
|
||||||
- `IWitsDataClient` - Клиент для работы с параметрами Wits
|
- `IWitsDataClient` - Клиент для работы с параметрами Wits
|
||||||
- `IDataSourceSystemClient` - Клиент для работы с системами
|
- `IDataSourceSystemClient` - Клиент для работы с системами
|
||||||
|
52
DD.Persistence.Client/RefitClientFactory.cs
Normal file
52
DD.Persistence.Client/RefitClientFactory.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
using DD.Persistence.Client.Helpers;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Refit;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Фабрика, которая создает refit-клиентов
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public class RefitClientFactory<T> : IRefitClientFactory<T> where T : IRefitClient
|
||||||
|
{
|
||||||
|
private HttpClient client;
|
||||||
|
private RefitSettings refitSettings;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public RefitClientFactory(IConfiguration configuration, ILogger<IRefitClientFactory<T>> logger, HttpClient client)
|
||||||
|
{
|
||||||
|
//this.client = factory.CreateClient();
|
||||||
|
this.client = client;
|
||||||
|
|
||||||
|
var baseUrl = configuration.GetSection("ClientUrl").Get<string>();
|
||||||
|
if (String.IsNullOrEmpty(baseUrl))
|
||||||
|
{
|
||||||
|
var exception = new SettingsPropertyNotFoundException("В настройках конфигурации не указан адрес Persistence сервиса.");
|
||||||
|
|
||||||
|
logger.LogError(exception.Message);
|
||||||
|
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
client.BaseAddress = new Uri(baseUrl);
|
||||||
|
|
||||||
|
JsonSerializerOptions JsonSerializerOptions = new()
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
refitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// создание клиента
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public T Create()
|
||||||
|
{
|
||||||
|
return RestService.For<T>(client, refitSettings);
|
||||||
|
}
|
||||||
|
}
|
20
DD.Persistence.Client/SetpointConfigStorage.cs
Normal file
20
DD.Persistence.Client/SetpointConfigStorage.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace DD.Persistence.Client;
|
||||||
|
internal class SetpointConfigStorage : ISetpointConfigStorage
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Guid, Type> setpointTypeConfigs;
|
||||||
|
|
||||||
|
public SetpointConfigStorage(Dictionary<Guid, Type>? setpointTypeConfigs)
|
||||||
|
{
|
||||||
|
this.setpointTypeConfigs = setpointTypeConfigs?? new Dictionary<Guid, Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetType(Guid id, out Type type)
|
||||||
|
{
|
||||||
|
return setpointTypeConfigs.TryGetValue(id, out type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddOrReplace(Guid id, Type type)
|
||||||
|
{
|
||||||
|
setpointTypeConfigs[id] = type;
|
||||||
|
}
|
||||||
|
}
|
135
DD.Persistence.Client/TimestampedSetMapper.cs
Normal file
135
DD.Persistence.Client/TimestampedSetMapper.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using DD.Persistence.Models;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client;
|
||||||
|
|
||||||
|
internal abstract class TimestampedSetMapperBase
|
||||||
|
{
|
||||||
|
public abstract object Map(TimestampedValuesDto data);
|
||||||
|
|
||||||
|
}
|
||||||
|
internal class TimestampedSetMapper<T> : TimestampedSetMapperBase
|
||||||
|
{
|
||||||
|
private readonly Type entityType = typeof(T);
|
||||||
|
public Guid IdDiscriminator { get; }
|
||||||
|
private readonly ConcurrentDictionary<string, PropertyInfo?> PropertyCache = new();
|
||||||
|
|
||||||
|
public TimestampedSetMapper(Guid idDiscriminator)
|
||||||
|
{
|
||||||
|
IdDiscriminator = idDiscriminator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object Map(TimestampedValuesDto data)
|
||||||
|
{
|
||||||
|
return DeserializeTimeStampedData(data)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T DeserializeTimeStampedData(TimestampedValuesDto data)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (entityType.IsValueType)
|
||||||
|
return MapStruct(data);
|
||||||
|
else
|
||||||
|
return MapClass(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private T MapClass(TimestampedValuesDto data)
|
||||||
|
{
|
||||||
|
var entity = (T)RuntimeHelpers.GetUninitializedObject(typeof(T));
|
||||||
|
foreach (var (propertyName, value) in data.Values)
|
||||||
|
{
|
||||||
|
if (value is JsonElement jsonElement)
|
||||||
|
SetPropertyValueFromJson(ref entity, propertyName, jsonElement);
|
||||||
|
}
|
||||||
|
SetPropertyValue(ref entity, "Timestamp", data.Timestamp);
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T MapStruct(TimestampedValuesDto data)
|
||||||
|
{
|
||||||
|
var entity = Activator.CreateInstance<T>();
|
||||||
|
object boxedEntity = entity!;
|
||||||
|
foreach (var (propertyName, value) in data.Values)
|
||||||
|
{
|
||||||
|
if (value is JsonElement jsonElement)
|
||||||
|
SetPropertyValueForStructFromJson(ref boxedEntity, propertyName, jsonElement);
|
||||||
|
}
|
||||||
|
SetPropertyValueForStruct(ref boxedEntity, "Timestamp", data.Timestamp);
|
||||||
|
|
||||||
|
return (T)boxedEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPropertyValueForStructFromJson(ref object entity, string propertyName, JsonElement element)
|
||||||
|
{
|
||||||
|
var property = GetPropertyInfo(propertyName);
|
||||||
|
if (property is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var value = element.Deserialize(property.PropertyType);
|
||||||
|
property.SetValue(entity, value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void SetPropertyValueForStruct(ref object entity, string propertyName, object value)
|
||||||
|
{
|
||||||
|
var property = GetPropertyInfo(propertyName);
|
||||||
|
if (property is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var convertedValue = Convert.ChangeType(value, property.PropertyType);
|
||||||
|
property.SetValue(entity, convertedValue);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void SetPropertyValueFromJson(ref T entity, string propertyName, JsonElement jsonElement)
|
||||||
|
{
|
||||||
|
var property = GetPropertyInfo(propertyName);
|
||||||
|
|
||||||
|
if (property is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var value = jsonElement.Deserialize(property.PropertyType);
|
||||||
|
property.SetValue(entity, value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPropertyValue(ref T entity, string propertyName, object value)
|
||||||
|
{
|
||||||
|
var property = GetPropertyInfo(propertyName);
|
||||||
|
if (property is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var convertedValue = Convert.ChangeType(value, property.PropertyType);
|
||||||
|
property.SetValue(entity, convertedValue);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertyInfo? GetPropertyInfo(string propertyName)
|
||||||
|
{
|
||||||
|
return PropertyCache.GetOrAdd(propertyName, name => entityType.GetProperty(name));
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
|
using System.Text.Json;
|
||||||
using DD.Persistence.Database.Model;
|
using DD.Persistence.Database.Model;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
@ -12,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace DD.Persistence.Database.Postgres.Migrations
|
namespace DD.Persistence.Database.Postgres.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PersistencePostgresContext))]
|
[DbContext(typeof(PersistencePostgresContext))]
|
||||||
[Migration("20241226122220_Init")]
|
[Migration("20250122120353_Init")]
|
||||||
partial class Init
|
partial class Init
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -25,6 +26,23 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("DD.Persistence.Database.Entity.DataScheme", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("DiscriminatorId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Идентификатор схемы данных");
|
||||||
|
|
||||||
|
b.Property<string>("PropNames")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasComment("Наименования полей в порядке индексации");
|
||||||
|
|
||||||
|
b.HasKey("DiscriminatorId");
|
||||||
|
|
||||||
|
b.ToTable("data_scheme");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
|
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("SystemId")
|
b.Property<Guid>("SystemId")
|
||||||
@ -105,27 +123,24 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
b.ToTable("tech_message");
|
b.ToTable("tech_message");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedSet", b =>
|
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedValues", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("IdDiscriminator")
|
b.Property<Guid>("DiscriminatorId")
|
||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasComment("Дискриминатор ссылка на тип сохраняемых данных");
|
.HasComment("Дискриминатор системы");
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("Timestamp")
|
b.Property<DateTimeOffset>("Timestamp")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasComment("Отметка времени, строго в UTC");
|
.HasComment("Временная отметка");
|
||||||
|
|
||||||
b.Property<string>("Set")
|
b.Property<string>("Values")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasComment("Набор сохраняемых данных");
|
.HasComment("Данные");
|
||||||
|
|
||||||
b.HasKey("IdDiscriminator", "Timestamp");
|
b.HasKey("DiscriminatorId", "Timestamp");
|
||||||
|
|
||||||
b.ToTable("timestamped_set", t =>
|
b.ToTable("timestamped_values");
|
||||||
{
|
|
||||||
t.HasComment("Общая таблица данных временных рядов");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DD.Persistence.Database.Model.ChangeLog", b =>
|
modelBuilder.Entity("DD.Persistence.Database.Model.ChangeLog", b =>
|
||||||
@ -181,96 +196,13 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
b.ToTable("change_log");
|
b.ToTable("change_log");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DD.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("data_saub");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("DD.Persistence.Database.Model.Setpoint", b =>
|
modelBuilder.Entity("DD.Persistence.Database.Model.Setpoint", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Key")
|
b.Property<Guid>("Key")
|
||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasComment("Ключ");
|
.HasComment("Ключ");
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("Created")
|
b.Property<DateTimeOffset>("Timestamp")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasComment("Дата создания уставки");
|
.HasComment("Дата создания уставки");
|
||||||
|
|
||||||
@ -278,12 +210,11 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasComment("Id автора последнего изменения");
|
.HasComment("Id автора последнего изменения");
|
||||||
|
|
||||||
b.Property<object>("Value")
|
b.Property<JsonElement>("Value")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasComment("Значение уставки");
|
.HasComment("Значение уставки");
|
||||||
|
|
||||||
b.HasKey("Key", "Created");
|
b.HasKey("Key", "Timestamp");
|
||||||
|
|
||||||
b.ToTable("setpoint");
|
b.ToTable("setpoint");
|
||||||
});
|
});
|
||||||
@ -298,6 +229,17 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
|
|
||||||
b.Navigation("System");
|
b.Navigation("System");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedValues", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DD.Persistence.Database.Entity.DataScheme", "DataScheme")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DiscriminatorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("DataScheme");
|
||||||
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Text.Json;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
@ -33,32 +34,15 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "data_saub",
|
name: "data_scheme",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
date = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
DiscriminatorId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"),
|
||||||
mode = table.Column<int>(type: "integer", nullable: true),
|
PropNames = table.Column<string>(type: "jsonb", nullable: false, comment: "Наименования полей в порядке индексации")
|
||||||
user = table.Column<string>(type: "text", nullable: true),
|
|
||||||
wellDepth = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
bitDepth = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
blockPosition = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
blockSpeed = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
pressure = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
axialLoad = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
hookWeight = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
rotorTorque = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
rotorSpeed = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
flow = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
mseState = table.Column<short>(type: "smallint", nullable: false),
|
|
||||||
idFeedRegulator = table.Column<int>(type: "integer", nullable: false),
|
|
||||||
mse = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
pump0Flow = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
pump1Flow = table.Column<double>(type: "double precision", nullable: true),
|
|
||||||
pump2Flow = table.Column<double>(type: "double precision", nullable: true)
|
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_data_saub", x => x.date);
|
table.PrimaryKey("PK_data_scheme", x => x.DiscriminatorId);
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
@ -93,28 +77,33 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
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: "Дата создания уставки"),
|
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата создания уставки"),
|
||||||
Value = table.Column<object>(type: "jsonb", nullable: false, comment: "Значение уставки"),
|
Value = table.Column<JsonElement>(type: "jsonb", nullable: false, comment: "Значение уставки"),
|
||||||
IdUser = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id автора последнего изменения")
|
IdUser = table.Column<Guid>(type: "uuid", nullable: false, comment: "Id автора последнего изменения")
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_setpoint", x => new { x.Key, x.Created });
|
table.PrimaryKey("PK_setpoint", x => new { x.Key, x.Timestamp });
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "timestamped_set",
|
name: "timestamped_values",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
IdDiscriminator = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор ссылка на тип сохраняемых данных"),
|
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Временная отметка"),
|
||||||
Timestamp = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Отметка времени, строго в UTC"),
|
DiscriminatorId = table.Column<Guid>(type: "uuid", nullable: false, comment: "Дискриминатор системы"),
|
||||||
Set = table.Column<string>(type: "jsonb", nullable: false, comment: "Набор сохраняемых данных")
|
Values = table.Column<string>(type: "jsonb", nullable: false, comment: "Данные")
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_timestamped_set", x => new { x.IdDiscriminator, x.Timestamp });
|
table.PrimaryKey("PK_timestamped_values", x => new { x.DiscriminatorId, x.Timestamp });
|
||||||
},
|
table.ForeignKey(
|
||||||
comment: "Общая таблица данных временных рядов");
|
name: "FK_timestamped_values_data_scheme_DiscriminatorId",
|
||||||
|
column: x => x.DiscriminatorId,
|
||||||
|
principalTable: "data_scheme",
|
||||||
|
principalColumn: "DiscriminatorId",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "tech_message",
|
name: "tech_message",
|
||||||
@ -153,9 +142,6 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "change_log");
|
name: "change_log");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "data_saub");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "parameter_data");
|
name: "parameter_data");
|
||||||
|
|
||||||
@ -166,10 +152,13 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
name: "tech_message");
|
name: "tech_message");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "timestamped_set");
|
name: "timestamped_values");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "data_source_system");
|
name: "data_source_system");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "data_scheme");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
|
using System.Text.Json;
|
||||||
using DD.Persistence.Database.Model;
|
using DD.Persistence.Database.Model;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
@ -22,6 +23,23 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("DD.Persistence.Database.Entity.DataScheme", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("DiscriminatorId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasComment("Идентификатор схемы данных");
|
||||||
|
|
||||||
|
b.Property<string>("PropNames")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasComment("Наименования полей в порядке индексации");
|
||||||
|
|
||||||
|
b.HasKey("DiscriminatorId");
|
||||||
|
|
||||||
|
b.ToTable("data_scheme");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
|
modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("SystemId")
|
b.Property<Guid>("SystemId")
|
||||||
@ -102,27 +120,24 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
b.ToTable("tech_message");
|
b.ToTable("tech_message");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedSet", b =>
|
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedValues", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("IdDiscriminator")
|
b.Property<Guid>("DiscriminatorId")
|
||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasComment("Дискриминатор ссылка на тип сохраняемых данных");
|
.HasComment("Дискриминатор системы");
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("Timestamp")
|
b.Property<DateTimeOffset>("Timestamp")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasComment("Отметка времени, строго в UTC");
|
.HasComment("Временная отметка");
|
||||||
|
|
||||||
b.Property<string>("Set")
|
b.Property<string>("Values")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasComment("Набор сохраняемых данных");
|
.HasComment("Данные");
|
||||||
|
|
||||||
b.HasKey("IdDiscriminator", "Timestamp");
|
b.HasKey("DiscriminatorId", "Timestamp");
|
||||||
|
|
||||||
b.ToTable("timestamped_set", t =>
|
b.ToTable("timestamped_values");
|
||||||
{
|
|
||||||
t.HasComment("Общая таблица данных временных рядов");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DD.Persistence.Database.Model.ChangeLog", b =>
|
modelBuilder.Entity("DD.Persistence.Database.Model.ChangeLog", b =>
|
||||||
@ -178,96 +193,13 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
b.ToTable("change_log");
|
b.ToTable("change_log");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DD.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("data_saub");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("DD.Persistence.Database.Model.Setpoint", b =>
|
modelBuilder.Entity("DD.Persistence.Database.Model.Setpoint", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Key")
|
b.Property<Guid>("Key")
|
||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasComment("Ключ");
|
.HasComment("Ключ");
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("Created")
|
b.Property<DateTimeOffset>("Timestamp")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasComment("Дата создания уставки");
|
.HasComment("Дата создания уставки");
|
||||||
|
|
||||||
@ -275,12 +207,11 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
.HasColumnType("uuid")
|
.HasColumnType("uuid")
|
||||||
.HasComment("Id автора последнего изменения");
|
.HasComment("Id автора последнего изменения");
|
||||||
|
|
||||||
b.Property<object>("Value")
|
b.Property<JsonElement>("Value")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasComment("Значение уставки");
|
.HasComment("Значение уставки");
|
||||||
|
|
||||||
b.HasKey("Key", "Created");
|
b.HasKey("Key", "Timestamp");
|
||||||
|
|
||||||
b.ToTable("setpoint");
|
b.ToTable("setpoint");
|
||||||
});
|
});
|
||||||
@ -295,6 +226,17 @@ namespace DD.Persistence.Database.Postgres.Migrations
|
|||||||
|
|
||||||
b.Navigation("System");
|
b.Navigation("System");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedValues", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DD.Persistence.Database.Entity.DataScheme", "DataScheme")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DiscriminatorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("DataScheme");
|
||||||
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using DD.Persistence.Models;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using DD.Persistence.ModelsAbstractions;
|
||||||
|
using DD.Persistence.Database.EntityAbstractions;
|
||||||
|
|
||||||
namespace DD.Persistence.Database.Model;
|
namespace DD.Persistence.Database.Model;
|
||||||
|
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Database.Model;
|
|
||||||
|
|
||||||
[Table("data_saub")]
|
|
||||||
public class DataSaub : ITimestampedData
|
|
||||||
{
|
|
||||||
[Key, Column("date")]
|
|
||||||
public DateTimeOffset Date { get; set; }
|
|
||||||
|
|
||||||
[Column("mode")]
|
|
||||||
public int? Mode { get; set; }
|
|
||||||
|
|
||||||
[Column("user")]
|
|
||||||
public string? User { get; set; }
|
|
||||||
|
|
||||||
[Column("wellDepth")]
|
|
||||||
public double? WellDepth { get; set; }
|
|
||||||
|
|
||||||
[Column("bitDepth")]
|
|
||||||
public double? BitDepth { get; set; }
|
|
||||||
|
|
||||||
[Column("blockPosition")]
|
|
||||||
public double? BlockPosition { get; set; }
|
|
||||||
|
|
||||||
[Column("blockSpeed")]
|
|
||||||
public double? BlockSpeed { get; set; }
|
|
||||||
|
|
||||||
[Column("pressure")]
|
|
||||||
public double? Pressure { get; set; }
|
|
||||||
|
|
||||||
[Column("axialLoad")]
|
|
||||||
public double? AxialLoad { get; set; }
|
|
||||||
|
|
||||||
[Column("hookWeight")]
|
|
||||||
public double? HookWeight { get; set; }
|
|
||||||
|
|
||||||
[Column("rotorTorque")]
|
|
||||||
public double? RotorTorque { get; set; }
|
|
||||||
|
|
||||||
[Column("rotorSpeed")]
|
|
||||||
public double? RotorSpeed { get; set; }
|
|
||||||
|
|
||||||
[Column("flow")]
|
|
||||||
public double? Flow { get; set; }
|
|
||||||
|
|
||||||
[Column("mseState")]
|
|
||||||
public short MseState { get; set; }
|
|
||||||
|
|
||||||
[Column("idFeedRegulator")]
|
|
||||||
public int IdFeedRegulator { get; set; }
|
|
||||||
|
|
||||||
[Column("mse")]
|
|
||||||
public double? Mse { get; set; }
|
|
||||||
|
|
||||||
[Column("pump0Flow")]
|
|
||||||
public double? Pump0Flow { get; set; }
|
|
||||||
|
|
||||||
[Column("pump1Flow")]
|
|
||||||
public double? Pump1Flow { get; set; }
|
|
||||||
|
|
||||||
[Column("pump2Flow")]
|
|
||||||
public double? Pump2Flow { get; set; }
|
|
||||||
}
|
|
15
DD.Persistence.Database/Entity/DataScheme.cs
Normal file
15
DD.Persistence.Database/Entity/DataScheme.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Database.Entity;
|
||||||
|
|
||||||
|
[Table("data_scheme")]
|
||||||
|
public class DataScheme
|
||||||
|
{
|
||||||
|
[Key, Comment("Идентификатор схемы данных"),]
|
||||||
|
public Guid DiscriminatorId { get; set; }
|
||||||
|
|
||||||
|
[Comment("Наименования полей в порядке индексации"), Column(TypeName = "jsonb")]
|
||||||
|
public string[] PropNames { get; set; } = [];
|
||||||
|
}
|
@ -11,7 +11,7 @@ public class DataSourceSystem
|
|||||||
public Guid SystemId { get; set; }
|
public Guid SystemId { get; set; }
|
||||||
|
|
||||||
[Required, Column(TypeName = "varchar(256)"), Comment("Наименование системы - источника данных")]
|
[Required, Column(TypeName = "varchar(256)"), Comment("Наименование системы - источника данных")]
|
||||||
public required string Name { get; set; }
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
[Comment("Описание системы - источника данных")]
|
[Comment("Описание системы - источника данных")]
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
namespace DD.Persistence.Database.Model;
|
|
||||||
public interface ITimestampedData
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Дата (должна быть обязательно в UTC)
|
|
||||||
/// </summary>
|
|
||||||
DateTimeOffset Date { get; set; }
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using DD.Persistence.Database.EntityAbstractions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
@ -6,7 +7,7 @@ namespace DD.Persistence.Database.Entity;
|
|||||||
|
|
||||||
[Table("parameter_data")]
|
[Table("parameter_data")]
|
||||||
[PrimaryKey(nameof(DiscriminatorId), nameof(ParameterId), nameof(Timestamp))]
|
[PrimaryKey(nameof(DiscriminatorId), nameof(ParameterId), nameof(Timestamp))]
|
||||||
public class ParameterData
|
public class ParameterData : ITimestampedItem
|
||||||
{
|
{
|
||||||
[Required, Comment("Дискриминатор системы")]
|
[Required, Comment("Дискриминатор системы")]
|
||||||
public Guid DiscriminatorId { get; set; }
|
public Guid DiscriminatorId { get; set; }
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using DD.Persistence.Database.EntityAbstractions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace DD.Persistence.Database.Model
|
namespace DD.Persistence.Database.Model
|
||||||
{
|
{
|
||||||
[Table("setpoint")]
|
[Table("setpoint")]
|
||||||
[PrimaryKey(nameof(Key), nameof(Created))]
|
[PrimaryKey(nameof(Key), nameof(Timestamp))]
|
||||||
public class Setpoint
|
public class Setpoint : ITimestampedItem
|
||||||
{
|
{
|
||||||
[Comment("Ключ")]
|
[Comment("Ключ")]
|
||||||
public Guid Key { get; set; }
|
public Guid Key { get; set; }
|
||||||
|
|
||||||
[Column(TypeName = "jsonb"), Comment("Значение уставки")]
|
[Column(TypeName = "jsonb"), Comment("Значение уставки")]
|
||||||
public required object Value { get; set; }
|
public required JsonElement Value { get; set; }
|
||||||
|
|
||||||
[Comment("Дата создания уставки")]
|
[Comment("Дата создания уставки")]
|
||||||
public DateTimeOffset Created { get; set; }
|
public DateTimeOffset Timestamp { get; set; }
|
||||||
|
|
||||||
[Comment("Id автора последнего изменения")]
|
[Comment("Id автора последнего изменения")]
|
||||||
public Guid IdUser { get; set; }
|
public Guid IdUser { get; set; }
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using DD.Persistence.Database.EntityAbstractions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
@ -5,7 +6,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||||||
namespace DD.Persistence.Database.Entity
|
namespace DD.Persistence.Database.Entity
|
||||||
{
|
{
|
||||||
[Table("tech_message")]
|
[Table("tech_message")]
|
||||||
public class TechMessage
|
public class TechMessage : ITimestampedItem
|
||||||
{
|
{
|
||||||
[Key, Comment("Id события")]
|
[Key, Comment("Id события")]
|
||||||
public Guid EventId { get; set; }
|
public Guid EventId { get; set; }
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace DD.Persistence.Database.Entity;
|
|
||||||
|
|
||||||
[Table("timestamped_set")]
|
|
||||||
[Comment("Общая таблица данных временных рядов")]
|
|
||||||
[PrimaryKey(nameof(IdDiscriminator), nameof(Timestamp))]
|
|
||||||
public record TimestampedSet(
|
|
||||||
[property: Comment("Дискриминатор ссылка на тип сохраняемых данных")] Guid IdDiscriminator,
|
|
||||||
[property: Comment("Отметка времени, строго в UTC")] DateTimeOffset Timestamp,
|
|
||||||
[property: Column(TypeName = "jsonb"), Comment("Набор сохраняемых данных")] IDictionary<string, object> Set);
|
|
23
DD.Persistence.Database/Entity/TimestampedValues.cs
Normal file
23
DD.Persistence.Database/Entity/TimestampedValues.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using DD.Persistence.Database.EntityAbstractions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Database.Entity;
|
||||||
|
|
||||||
|
[Table("timestamped_values")]
|
||||||
|
[PrimaryKey(nameof(DiscriminatorId), nameof(Timestamp))]
|
||||||
|
public class TimestampedValues : ITimestampedItem
|
||||||
|
{
|
||||||
|
[Comment("Временная отметка"), Key]
|
||||||
|
public DateTimeOffset Timestamp { get; set; }
|
||||||
|
|
||||||
|
[Comment("Дискриминатор системы"),]
|
||||||
|
public Guid DiscriminatorId { get; set; }
|
||||||
|
|
||||||
|
[Comment("Данные"), Column(TypeName = "jsonb")]
|
||||||
|
public required object[] Values { get; set; }
|
||||||
|
|
||||||
|
[Required, ForeignKey(nameof(DiscriminatorId)), Comment("Идентификаторы")]
|
||||||
|
public virtual DataScheme? DataScheme { get; set; }
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
|
namespace DD.Persistence.Database.EntityAbstractions;
|
||||||
namespace DD.Persistence.Database.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Часть записи, описывающая изменение
|
/// Часть записи, описывающая изменение
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace DD.Persistence.Database.EntityAbstractions;
|
||||||
|
public interface ITimestampedItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Дата (должна быть обязательно в UTC)
|
||||||
|
/// </summary>
|
||||||
|
DateTimeOffset Timestamp { get; set; }
|
||||||
|
}
|
@ -9,11 +9,11 @@ namespace DD.Persistence.Database;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PersistenceDbContext : DbContext
|
public class PersistenceDbContext : DbContext
|
||||||
{
|
{
|
||||||
public DbSet<DataSaub> DataSaub => Set<DataSaub>();
|
|
||||||
|
|
||||||
public DbSet<Setpoint> Setpoint => Set<Setpoint>();
|
public DbSet<Setpoint> Setpoint => Set<Setpoint>();
|
||||||
|
|
||||||
public DbSet<TimestampedSet> TimestampedSets => Set<TimestampedSet>();
|
public DbSet<DataScheme> DataSchemes => Set<DataScheme>();
|
||||||
|
|
||||||
|
public DbSet<TimestampedValues> TimestampedValues => Set<TimestampedValues>();
|
||||||
|
|
||||||
public DbSet<ChangeLog> ChangeLog => Set<ChangeLog>();
|
public DbSet<ChangeLog> ChangeLog => Set<ChangeLog>();
|
||||||
|
|
||||||
@ -31,8 +31,12 @@ public class PersistenceDbContext : DbContext
|
|||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
modelBuilder.Entity<TimestampedSet>()
|
modelBuilder.Entity<DataScheme>()
|
||||||
.Property(e => e.Set)
|
.Property(e => e.PropNames)
|
||||||
|
.HasJsonConversion();
|
||||||
|
|
||||||
|
modelBuilder.Entity<TimestampedValues>()
|
||||||
|
.Property(e => e.Values)
|
||||||
.HasJsonConversion();
|
.HasJsonConversion();
|
||||||
|
|
||||||
modelBuilder.Entity<ChangeLog>()
|
modelBuilder.Entity<ChangeLog>()
|
||||||
|
@ -7,6 +7,11 @@ using DD.Persistence.Models.Requests;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
using DD.Persistence.Client;
|
using DD.Persistence.Client;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
using DD.Persistence.Client.Clients;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Refit;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests.Controllers;
|
namespace DD.Persistence.IntegrationTests.Controllers;
|
||||||
public class ChangeLogControllerTest : BaseIntegrationTest
|
public class ChangeLogControllerTest : BaseIntegrationTest
|
||||||
@ -16,10 +21,12 @@ public class ChangeLogControllerTest : BaseIntegrationTest
|
|||||||
|
|
||||||
public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
var refitClientFactory = scope.ServiceProvider
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
.GetRequiredService<IRefitClientFactory<IRefitChangeLogClient>>();
|
||||||
|
var logger = scope.ServiceProvider.GetRequiredService<ILogger<ChangeLogClient>>();
|
||||||
|
|
||||||
client = persistenceClientFactory.GetChangeLogClient();
|
client = scope.ServiceProvider
|
||||||
|
.GetRequiredService<IChangeLogClient>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
using DD.Persistence.Database.Model;
|
|
||||||
using DD.Persistence.Models;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests.Controllers;
|
|
||||||
public class DataSaubControllerTest : TimeSeriesBaseControllerTest<DataSaub, DataSaubDto>
|
|
||||||
{
|
|
||||||
private readonly DataSaubDto dto = new()
|
|
||||||
{
|
|
||||||
AxialLoad = 1,
|
|
||||||
BitDepth = 2,
|
|
||||||
BlockPosition = 3,
|
|
||||||
BlockSpeed = 4,
|
|
||||||
Date = DateTimeOffset.UtcNow,
|
|
||||||
Flow = 5,
|
|
||||||
HookWeight = 6,
|
|
||||||
IdFeedRegulator = 8,
|
|
||||||
Mode = 9,
|
|
||||||
Mse = 10,
|
|
||||||
MseState = 11,
|
|
||||||
Pressure = 12,
|
|
||||||
Pump0Flow = 13,
|
|
||||||
Pump1Flow = 14,
|
|
||||||
Pump2Flow = 15,
|
|
||||||
RotorSpeed = 16,
|
|
||||||
RotorTorque = 17,
|
|
||||||
User = string.Empty,
|
|
||||||
WellDepth = 18,
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly DataSaub entity = new()
|
|
||||||
{
|
|
||||||
AxialLoad = 1,
|
|
||||||
BitDepth = 2,
|
|
||||||
BlockPosition = 3,
|
|
||||||
BlockSpeed = 4,
|
|
||||||
Date = DateTimeOffset.UtcNow,
|
|
||||||
Flow = 5,
|
|
||||||
HookWeight = 6,
|
|
||||||
IdFeedRegulator = 8,
|
|
||||||
Mode = 9,
|
|
||||||
Mse = 10,
|
|
||||||
MseState = 11,
|
|
||||||
Pressure = 12,
|
|
||||||
Pump0Flow = 13,
|
|
||||||
Pump1Flow = 14,
|
|
||||||
Pump2Flow = 15,
|
|
||||||
RotorSpeed = 16,
|
|
||||||
RotorTorque = 17,
|
|
||||||
User = string.Empty,
|
|
||||||
WellDepth = 18,
|
|
||||||
};
|
|
||||||
|
|
||||||
public DataSaubControllerTest(WebAppFactoryFixture factory) : base(factory)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task InsertRange_returns_success()
|
|
||||||
{
|
|
||||||
await InsertRangeSuccess(dto);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Get_returns_success()
|
|
||||||
{
|
|
||||||
var beginDate = DateTimeOffset.UtcNow.AddDays(-1);
|
|
||||||
var endDate = DateTimeOffset.UtcNow;
|
|
||||||
await GetSuccess(beginDate, endDate, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetDatesRange_returns_success()
|
|
||||||
{
|
|
||||||
await GetDatesRangeSuccess(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetResampledData_returns_success()
|
|
||||||
{
|
|
||||||
await GetResampledDataSuccess(entity);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,8 @@ using DD.Persistence.Client.Clients.Interfaces;
|
|||||||
using DD.Persistence.Database.Entity;
|
using DD.Persistence.Database.Entity;
|
||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests.Controllers
|
namespace DD.Persistence.IntegrationTests.Controllers
|
||||||
{
|
{
|
||||||
@ -16,11 +18,12 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
private readonly IMemoryCache memoryCache;
|
private readonly IMemoryCache memoryCache;
|
||||||
public DataSourceSystemControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public DataSourceSystemControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
var scope = factory.Services.CreateScope();
|
var refitClientFactory = scope.ServiceProvider
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
.GetRequiredService<IRefitClientFactory<IRefitDataSourceSystemClient>>();
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
var logger = scope.ServiceProvider.GetRequiredService<ILogger<DataSourceSystemClient>>();
|
||||||
|
|
||||||
dataSourceSystemClient = persistenceClientFactory.GetDataSourceSystemClient();
|
dataSourceSystemClient = scope.ServiceProvider
|
||||||
|
.GetRequiredService<IDataSourceSystemClient>();
|
||||||
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using DD.Persistence.Client;
|
using DD.Persistence.Client;
|
||||||
|
using DD.Persistence.Client.Clients;
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
using DD.Persistence.Database.Model;
|
using DD.Persistence.Database.Model;
|
||||||
using System.Net;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Text.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests.Controllers
|
namespace DD.Persistence.IntegrationTests.Controllers
|
||||||
@ -10,20 +13,45 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
public class SetpointControllerTest : BaseIntegrationTest
|
public class SetpointControllerTest : BaseIntegrationTest
|
||||||
{
|
{
|
||||||
private readonly ISetpointClient setpointClient;
|
private readonly ISetpointClient setpointClient;
|
||||||
private class TestObject
|
private readonly SetpointConfigStorage configStorage;
|
||||||
{
|
|
||||||
public string? Value1 { get; set; }
|
|
||||||
public int? Value2 { get; set; }
|
|
||||||
}
|
|
||||||
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
var scope = factory.Services.CreateScope();
|
var refitClientFactory = scope.ServiceProvider
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
.GetRequiredService<IRefitClientFactory<IRefitSetpointClient>>();
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
var logger = scope.ServiceProvider.GetRequiredService<ILogger<SetpointClient>>();
|
||||||
|
|
||||||
setpointClient = persistenceClientFactory.GetSetpointClient();
|
setpointClient = scope.ServiceProvider
|
||||||
|
.GetRequiredService<ISetpointClient>();
|
||||||
|
|
||||||
|
configStorage = (SetpointConfigStorage)scope.ServiceProvider.GetRequiredService<ISetpointConfigStorage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetCurrent_returns_correctType()
|
||||||
|
{
|
||||||
|
var id = Guid.Parse("e0fcad22-1761-476e-a729-a3c59d51ba41");
|
||||||
|
|
||||||
|
configStorage.AddOrReplace(id, typeof(float));
|
||||||
|
|
||||||
|
await setpointClient.Add(id, 48.3f, CancellationToken.None);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await setpointClient.GetCurrent([id], CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.NotEmpty(response);
|
||||||
|
Assert.Single(response);
|
||||||
|
var item = response.First();
|
||||||
|
Assert.Equal(item.Key, id);
|
||||||
|
|
||||||
|
Assert.IsNotType<JsonElement>(item.Value);
|
||||||
|
Assert.Equal(item.Value, 48.3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetCurrent_returns_success()
|
public async Task GetCurrent_returns_success()
|
||||||
{
|
{
|
||||||
@ -35,7 +63,7 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
};
|
};
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await setpointClient.GetCurrent(setpointKeys, new CancellationToken());
|
var response = await setpointClient.GetCurrent(setpointKeys, CancellationToken.None);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
@ -149,7 +177,7 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
|
|
||||||
await Add();
|
await Add();
|
||||||
|
|
||||||
var dateBegin = DateTimeOffset.MinValue;
|
var dateBegin = DateTimeOffset.UtcNow.AddDays(-1);
|
||||||
var take = 1;
|
var take = 1;
|
||||||
var part = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);
|
var part = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);
|
||||||
|
|
||||||
@ -160,14 +188,17 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
|
|
||||||
var expectedValue = part!
|
var expectedValue = part!
|
||||||
.FirstOrDefault()!.Created
|
.FirstOrDefault()!.Timestamp
|
||||||
.ToString("dd.MM.yyyy-HH:mm:ss");
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
var actualValueFrom = response.From
|
var actualValueFrom = response.From
|
||||||
.ToString("dd.MM.yyyy-HH:mm:ss");
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
Assert.Equal(expectedValue, actualValueFrom);
|
Assert.Equal(expectedValue, actualValueFrom);
|
||||||
|
|
||||||
var actualValueTo = response.To
|
var actualValueTo = response.To
|
||||||
.ToString("dd.MM.yyyy-HH:mm:ss");
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
Assert.Equal(expectedValue, actualValueTo);
|
Assert.Equal(expectedValue, actualValueTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +243,7 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
var setpointKey = Guid.NewGuid();
|
var setpointKey = Guid.NewGuid();
|
||||||
var setpointValue = new TestObject()
|
var setpointValue = new
|
||||||
{
|
{
|
||||||
Value1 = "1",
|
Value1 = "1",
|
||||||
Value2 = 2
|
Value2 = 2
|
||||||
|
@ -1,38 +1,41 @@
|
|||||||
using Microsoft.Extensions.Caching.Memory;
|
using DD.Persistence.Client;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using DD.Persistence.Client.Clients;
|
||||||
using DD.Persistence.Client;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
using DD.Persistence.Database.Entity;
|
using DD.Persistence.Database.Entity;
|
||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
using DD.Persistence.Models.Enumerations;
|
using DD.Persistence.Models.Enumerations;
|
||||||
using DD.Persistence.Models.Requests;
|
using DD.Persistence.Models.Requests;
|
||||||
using System.Net;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests.Controllers
|
namespace DD.Persistence.IntegrationTests.Controllers
|
||||||
{
|
{
|
||||||
public class TechMessagesControllerTest : BaseIntegrationTest
|
public class TechMessagesControllerTest : BaseIntegrationTest
|
||||||
{
|
{
|
||||||
private static readonly string SystemCacheKey = $"{typeof(Database.Entity.DataSourceSystem).FullName}CacheKey";
|
private static readonly string SystemCacheKey = $"{typeof(DataSourceSystem).FullName}CacheKey";
|
||||||
private readonly ITechMessagesClient techMessagesClient;
|
private readonly ITechMessagesClient techMessagesClient;
|
||||||
private readonly IMemoryCache memoryCache;
|
private readonly IMemoryCache memoryCache;
|
||||||
public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public TechMessagesControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
var scope = factory.Services.CreateScope();
|
var refitClientFactory = scope.ServiceProvider
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
.GetRequiredService<IRefitClientFactory<IRefitTechMessagesClient>>();
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TechMessagesClient>>();
|
||||||
|
|
||||||
techMessagesClient = persistenceClientFactory.GetTechMessagesClient();
|
techMessagesClient = scope.ServiceProvider
|
||||||
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
.GetRequiredService<ITechMessagesClient>();
|
||||||
}
|
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetPage_returns_success()
|
public async Task GetPage_returns_success()
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
memoryCache.Remove(SystemCacheKey);
|
memoryCache.Remove(SystemCacheKey);
|
||||||
dbContext.CleanupDbSet<TechMessage>();
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
dbContext.CleanupDbSet<DataSourceSystem>();
|
dbContext.CleanupDbSet<DataSourceSystem>();
|
||||||
|
|
||||||
var requestDto = new PaginationRequest()
|
var requestDto = new PaginationRequest()
|
||||||
{
|
{
|
||||||
@ -44,235 +47,235 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
//act
|
//act
|
||||||
var response = await techMessagesClient.GetPage(requestDto, CancellationToken.None);
|
var response = await techMessagesClient.GetPage(requestDto, CancellationToken.None);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
Assert.Empty(response.Items);
|
Assert.Empty(response.Items);
|
||||||
Assert.Equal(requestDto.Skip, response.Skip);
|
Assert.Equal(requestDto.Skip, response.Skip);
|
||||||
Assert.Equal(requestDto.Take, response.Take);
|
Assert.Equal(requestDto.Take, response.Take);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetPage_AfterSave_returns_success()
|
public async Task GetPage_AfterSave_returns_success()
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
var dtos = await InsertRange(Guid.NewGuid());
|
var dtos = await InsertRange(Guid.NewGuid());
|
||||||
var dtosCount = dtos.Count();
|
var dtosCount = dtos.Count();
|
||||||
var requestDto = new PaginationRequest()
|
var requestDto = new PaginationRequest()
|
||||||
{
|
{
|
||||||
Skip = 0,
|
Skip = 0,
|
||||||
Take = 2,
|
Take = 2,
|
||||||
SortSettings = nameof(TechMessage.CategoryId)
|
SortSettings = nameof(TechMessage.CategoryId)
|
||||||
};
|
};
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await techMessagesClient.GetPage(requestDto, CancellationToken.None);
|
var response = await techMessagesClient.GetPage(requestDto, CancellationToken.None);
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(dtosCount, response.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task InsertRange_returns_success()
|
|
||||||
{
|
|
||||||
await InsertRange(Guid.NewGuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task InsertRange_returns_BadRequest()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
const string exceptionMessage = "Ошибка валидации, формата или маршрутизации запроса";
|
|
||||||
var systemId = Guid.NewGuid();
|
|
||||||
var dtos = new List<TechMessageDto>()
|
|
||||||
{
|
|
||||||
new TechMessageDto()
|
|
||||||
{
|
|
||||||
EventId = Guid.NewGuid(),
|
|
||||||
CategoryId = -1, // < 0
|
|
||||||
Timestamp = DateTimeOffset.UtcNow,
|
|
||||||
Text = string.Empty, // length < 0
|
|
||||||
EventState = EventState.Triggered
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//act
|
|
||||||
var response = await techMessagesClient.AddRange(systemId, dtos, CancellationToken.None);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
//assert
|
|
||||||
Assert.Equal(exceptionMessage, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetSystems_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
memoryCache.Remove(SystemCacheKey);
|
|
||||||
dbContext.CleanupDbSet<TechMessage>();
|
|
||||||
dbContext.CleanupDbSet<DataSourceSystem>();
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await techMessagesClient.GetSystems(CancellationToken.None);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Empty(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetSystems_AfterSave_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
await InsertRange(Guid.NewGuid());
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await techMessagesClient.GetSystems(CancellationToken.None);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
var expectedSystemCount = 1;
|
|
||||||
Assert.Equal(expectedSystemCount, response!.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetStatistics_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
memoryCache.Remove(SystemCacheKey);
|
|
||||||
dbContext.CleanupDbSet<TechMessage>();
|
|
||||||
dbContext.CleanupDbSet<DataSourceSystem>();
|
|
||||||
|
|
||||||
var categoryIds = new [] { 1, 2 };
|
|
||||||
var systemIds = new [] { Guid.NewGuid() };
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await techMessagesClient.GetStatistics(systemIds, categoryIds, CancellationToken.None);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Empty(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetStatistics_AfterSave_returns_success()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var categoryIds = new[] { 1 };
|
|
||||||
var systemId = Guid.NewGuid();
|
|
||||||
var dtos = await InsertRange(systemId);
|
|
||||||
var filteredDtos = dtos.Where(e => categoryIds.Contains(e.CategoryId));
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await techMessagesClient.GetStatistics([systemId], categoryIds, CancellationToken.None);
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.NotEmpty(response);
|
|
||||||
var categories = response
|
|
||||||
.FirstOrDefault()!.Categories
|
|
||||||
.Count();
|
|
||||||
Assert.Equal(filteredDtos.Count(), categories);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetDatesRange_returns_NoContent()
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
memoryCache.Remove(SystemCacheKey);
|
|
||||||
dbContext.CleanupDbSet<TechMessage>();
|
|
||||||
dbContext.CleanupDbSet<DataSourceSystem>();
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await techMessagesClient.GetDatesRangeAsync(CancellationToken.None);
|
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Null(response);
|
Assert.NotNull(response);
|
||||||
}
|
Assert.Equal(dtosCount, response.Count);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetDatesRange_AfterSave_returns_success()
|
public async Task InsertRange_returns_success()
|
||||||
{
|
{
|
||||||
//arrange
|
await InsertRange(Guid.NewGuid());
|
||||||
await InsertRange(Guid.NewGuid());
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InsertRange_returns_BadRequest()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
const string exceptionMessage = "Ошибка валидации, формата или маршрутизации запроса";
|
||||||
|
var systemId = Guid.NewGuid();
|
||||||
|
var dtos = new List<TechMessageDto>()
|
||||||
|
{
|
||||||
|
new TechMessageDto()
|
||||||
|
{
|
||||||
|
EventId = Guid.NewGuid(),
|
||||||
|
CategoryId = -1, // < 0
|
||||||
|
Timestamp = DateTimeOffset.UtcNow,
|
||||||
|
Text = string.Empty, // length < 0
|
||||||
|
EventState = EventState.Triggered
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.AddRange(systemId, dtos, CancellationToken.None);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
//assert
|
||||||
|
Assert.Equal(exceptionMessage, ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetSystems_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
memoryCache.Remove(SystemCacheKey);
|
||||||
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
|
dbContext.CleanupDbSet<DataSourceSystem>();
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetSystems(CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.Empty(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetSystems_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
await InsertRange(Guid.NewGuid());
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetSystems(CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
var expectedSystemCount = 1;
|
||||||
|
Assert.Equal(expectedSystemCount, response!.Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetStatistics_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
memoryCache.Remove(SystemCacheKey);
|
||||||
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
|
dbContext.CleanupDbSet<DataSourceSystem>();
|
||||||
|
|
||||||
|
var categoryIds = new[] { 1, 2 };
|
||||||
|
var systemIds = new[] { Guid.NewGuid() };
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetStatistics(systemIds, categoryIds, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.Empty(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetStatistics_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var categoryIds = new[] { 1 };
|
||||||
|
var systemId = Guid.NewGuid();
|
||||||
|
var dtos = await InsertRange(systemId);
|
||||||
|
var filteredDtos = dtos.Where(e => categoryIds.Contains(e.CategoryId));
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await techMessagesClient.GetStatistics([systemId], categoryIds, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.NotEmpty(response);
|
||||||
|
var categories = response
|
||||||
|
.FirstOrDefault()!.Categories
|
||||||
|
.Count();
|
||||||
|
Assert.Equal(filteredDtos.Count(), categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetDatesRange_returns_NoContent()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
memoryCache.Remove(SystemCacheKey);
|
||||||
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
|
dbContext.CleanupDbSet<DataSourceSystem>();
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await techMessagesClient.GetDatesRangeAsync(CancellationToken.None);
|
var response = await techMessagesClient.GetDatesRangeAsync(CancellationToken.None);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.NotNull(response);
|
Assert.Null(response);
|
||||||
Assert.NotNull(response?.From);
|
}
|
||||||
Assert.NotNull(response?.To);
|
|
||||||
}
|
|
||||||
|
|
||||||
// [Fact]
|
[Fact]
|
||||||
// public async Task GetPart_returns_success()
|
public async Task GetDatesRange_AfterSave_returns_success()
|
||||||
// {
|
{
|
||||||
// //arrange
|
//arrange
|
||||||
// var dateBegin = DateTimeOffset.UtcNow;
|
await InsertRange(Guid.NewGuid());
|
||||||
// var take = 2;
|
|
||||||
|
|
||||||
// //act
|
//act
|
||||||
// var response = await techMessagesClient.GetPart(dateBegin, take, CancellationToken.None);
|
var response = await techMessagesClient.GetDatesRangeAsync(CancellationToken.None);
|
||||||
|
|
||||||
// //assert
|
//assert
|
||||||
// Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
// Assert.Empty(response);
|
Assert.NotNull(response?.From);
|
||||||
//}
|
Assert.NotNull(response?.To);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
// [Fact]
|
||||||
public async Task GetPart_AfterSave_returns_success()
|
// public async Task GetPart_returns_success()
|
||||||
{
|
// {
|
||||||
//arrange
|
// //arrange
|
||||||
var dateBegin = DateTimeOffset.UtcNow;
|
// var dateBegin = DateTimeOffset.UtcNow;
|
||||||
var take = 1;
|
// var take = 2;
|
||||||
await InsertRange(Guid.NewGuid());
|
|
||||||
|
// //act
|
||||||
|
// var response = await techMessagesClient.GetPart(dateBegin, take, CancellationToken.None);
|
||||||
|
|
||||||
|
// //assert
|
||||||
|
// Assert.NotNull(response);
|
||||||
|
// Assert.Empty(response);
|
||||||
|
//}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetPart_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
var dateBegin = DateTimeOffset.UtcNow;
|
||||||
|
var take = 1;
|
||||||
|
await InsertRange(Guid.NewGuid());
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await techMessagesClient.GetPart(dateBegin, take, CancellationToken.None);
|
var response = await techMessagesClient.GetPart(dateBegin, take, CancellationToken.None);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
Assert.NotEmpty(response);
|
Assert.NotEmpty(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<TechMessageDto>> InsertRange(Guid systemId)
|
private async Task<IEnumerable<TechMessageDto>> InsertRange(Guid systemId)
|
||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
memoryCache.Remove(SystemCacheKey);
|
memoryCache.Remove(SystemCacheKey);
|
||||||
dbContext.CleanupDbSet<TechMessage>();
|
dbContext.CleanupDbSet<TechMessage>();
|
||||||
dbContext.CleanupDbSet<DataSourceSystem>();
|
dbContext.CleanupDbSet<DataSourceSystem>();
|
||||||
|
|
||||||
var dtos = new List<TechMessageDto>()
|
var dtos = new List<TechMessageDto>()
|
||||||
{
|
{
|
||||||
new TechMessageDto()
|
new TechMessageDto()
|
||||||
{
|
{
|
||||||
EventId = Guid.NewGuid(),
|
EventId = Guid.NewGuid(),
|
||||||
CategoryId = 1,
|
CategoryId = 1,
|
||||||
Timestamp = DateTimeOffset.UtcNow,
|
Timestamp = DateTimeOffset.UtcNow,
|
||||||
Text = nameof(TechMessageDto.Text),
|
Text = nameof(TechMessageDto.Text),
|
||||||
EventState = Models.Enumerations.EventState.Triggered
|
EventState = Models.Enumerations.EventState.Triggered
|
||||||
},
|
},
|
||||||
new TechMessageDto()
|
new TechMessageDto()
|
||||||
{
|
{
|
||||||
EventId = Guid.NewGuid(),
|
EventId = Guid.NewGuid(),
|
||||||
CategoryId = 2,
|
CategoryId = 2,
|
||||||
Timestamp = DateTimeOffset.UtcNow,
|
Timestamp = DateTimeOffset.UtcNow,
|
||||||
Text = nameof(TechMessageDto.Text),
|
Text = nameof(TechMessageDto.Text),
|
||||||
EventState = Models.Enumerations.EventState.Triggered
|
EventState = Models.Enumerations.EventState.Triggered
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await techMessagesClient.AddRange(systemId, dtos, CancellationToken.None);
|
var response = await techMessagesClient.AddRange(systemId, dtos, CancellationToken.None);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.Equal(dtos.Count, response);
|
Assert.Equal(dtos.Count, response);
|
||||||
|
|
||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
using Mapster;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using DD.Persistence.Client;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
|
||||||
using DD.Persistence.Database.Model;
|
|
||||||
using System.Net;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests.Controllers;
|
|
||||||
|
|
||||||
public abstract class TimeSeriesBaseControllerTest<TEntity, TDto> : BaseIntegrationTest
|
|
||||||
where TEntity : class, ITimestampedData, new()
|
|
||||||
where TDto : class, new()
|
|
||||||
{
|
|
||||||
private readonly ITimeSeriesClient<TDto> timeSeriesClient;
|
|
||||||
|
|
||||||
public TimeSeriesBaseControllerTest(WebAppFactoryFixture factory) : base(factory)
|
|
||||||
{
|
|
||||||
dbContext.CleanupDbSet<TEntity>();
|
|
||||||
|
|
||||||
var scope = factory.Services.CreateScope();
|
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
|
||||||
|
|
||||||
timeSeriesClient = persistenceClientFactory.GetTimeSeriesClient<TDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InsertRangeSuccess(TDto dto)
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var expected = dto.Adapt<TDto>();
|
|
||||||
|
|
||||||
//act
|
|
||||||
var response = await timeSeriesClient.AddRange(new TDto[] { expected }, new CancellationToken());
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.Equal(1, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task GetSuccess(DateTimeOffset beginDate, DateTimeOffset endDate, TEntity entity)
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var dbset = dbContext.Set<TEntity>();
|
|
||||||
|
|
||||||
dbset.Add(entity);
|
|
||||||
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
|
|
||||||
var response = await timeSeriesClient.Get(beginDate, endDate, new CancellationToken());
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Single(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task GetDatesRangeSuccess(TEntity entity)
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var datesRangeExpected = 30;
|
|
||||||
|
|
||||||
var entity2 = entity.Adapt<TEntity>();
|
|
||||||
entity2.Date = entity.Date.AddDays(datesRangeExpected);
|
|
||||||
|
|
||||||
var dbset = dbContext.Set<TEntity>();
|
|
||||||
dbset.Add(entity);
|
|
||||||
dbset.Add(entity2);
|
|
||||||
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
|
|
||||||
var response = await timeSeriesClient.GetDatesRange(new CancellationToken());
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
|
|
||||||
var datesRangeActual = (response.To - response.From).Days;
|
|
||||||
Assert.Equal(datesRangeExpected, datesRangeActual);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task GetResampledDataSuccess(TEntity entity)
|
|
||||||
{
|
|
||||||
//arrange
|
|
||||||
var approxPointsCount = 10;
|
|
||||||
var differenceBetweenStartAndEndDays = 50;
|
|
||||||
|
|
||||||
var entities = new List<TEntity>();
|
|
||||||
for (var i = 1; i <= differenceBetweenStartAndEndDays; i++)
|
|
||||||
{
|
|
||||||
var entity2 = entity.Adapt<TEntity>();
|
|
||||||
entity2.Date = entity.Date.AddDays(i - 1);
|
|
||||||
|
|
||||||
entities.Add(entity2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var dbset = dbContext.Set<TEntity>();
|
|
||||||
dbset.AddRange(entities);
|
|
||||||
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
|
|
||||||
var response = await timeSeriesClient.GetResampledData(entity.Date.AddMinutes(-1), differenceBetweenStartAndEndDays * 24 * 60 * 60 + 60, approxPointsCount, new CancellationToken());
|
|
||||||
|
|
||||||
//assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
|
|
||||||
var ratio = entities.Count / approxPointsCount;
|
|
||||||
if (ratio > 1)
|
|
||||||
{
|
|
||||||
var expectedResampledCount = entities
|
|
||||||
.Where((_, index) => index % ratio == 0)
|
|
||||||
.Count();
|
|
||||||
|
|
||||||
Assert.Equal(expectedResampledCount, response.Count());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.Equal(entities.Count(), response.Count());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,206 +0,0 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using DD.Persistence.Client;
|
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
|
||||||
using DD.Persistence.Models;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests.Controllers;
|
|
||||||
public class TimestampedSetControllerTest : BaseIntegrationTest
|
|
||||||
{
|
|
||||||
private readonly ITimestampedSetClient client;
|
|
||||||
|
|
||||||
public TimestampedSetControllerTest(WebAppFactoryFixture factory) : base(factory)
|
|
||||||
{
|
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
|
||||||
|
|
||||||
client = persistenceClientFactory.GetTimestampedSetClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task InsertRange()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(10, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.Equal(testSets.Count(), response);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Get_without_filter()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
int count = 10;
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.Get(idDiscriminator, null, null, 0, int.MaxValue, CancellationToken.None);
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(count, response.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Get_with_filter_props()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
int count = 10;
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
string[] props = ["A"];
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.Get(idDiscriminator, null, props, 0, int.MaxValue, new CancellationToken());
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(count, response.Count());
|
|
||||||
foreach (var item in response)
|
|
||||||
{
|
|
||||||
Assert.Single(item.Set);
|
|
||||||
var kv = item.Set.First();
|
|
||||||
Assert.Equal("A", kv.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Get_geDate()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
int count = 10;
|
|
||||||
var dateMin = DateTimeOffset.Now;
|
|
||||||
var dateMax = DateTimeOffset.Now.AddSeconds(count);
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
var insertResponse = await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
var tail = testSets.OrderBy(t => t.Timestamp).Skip(count / 2).Take(int.MaxValue);
|
|
||||||
var geDate = tail.First().Timestamp;
|
|
||||||
var tolerance = TimeSpan.FromSeconds(1);
|
|
||||||
var expectedCount = tail.Count();
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.Get(idDiscriminator, geDate, null, 0, int.MaxValue, CancellationToken.None);
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(expectedCount, response.Count());
|
|
||||||
var minDate = response.Min(t => t.Timestamp);
|
|
||||||
Assert.Equal(geDate, geDate, tolerance);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Get_with_skip_take()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
int count = 10;
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
var expectedCount = count / 2;
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.Get(idDiscriminator, null, null, 2, expectedCount, new CancellationToken());
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(expectedCount, response.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Get_with_big_skip_take()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
var expectedCount = 1;
|
|
||||||
int count = 10 + expectedCount;
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.Get(idDiscriminator, null, null, count - expectedCount, count, new CancellationToken());
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(expectedCount, response.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetLast()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
int count = 10;
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
var expectedCount = 8;
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.GetLast(idDiscriminator, null, expectedCount, new CancellationToken());
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(expectedCount, response.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task GetDatesRange()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
int count = 10;
|
|
||||||
var dateMin = DateTimeOffset.Now;
|
|
||||||
var dateMax = DateTimeOffset.Now.AddSeconds(count - 1);
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, dateMin.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
var tolerance = TimeSpan.FromSeconds(1);
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.GetDatesRange(idDiscriminator, new CancellationToken());
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(dateMin, response.From, tolerance);
|
|
||||||
Assert.Equal(dateMax, response.To, tolerance);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Count()
|
|
||||||
{
|
|
||||||
// arrange
|
|
||||||
Guid idDiscriminator = Guid.NewGuid();
|
|
||||||
int count = 144;
|
|
||||||
IEnumerable<TimestampedSetDto> testSets = Generate(count, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
|
||||||
await client.AddRange(idDiscriminator, testSets, CancellationToken.None);
|
|
||||||
|
|
||||||
// act
|
|
||||||
var response = await client.Count(idDiscriminator, new CancellationToken());
|
|
||||||
|
|
||||||
// assert
|
|
||||||
Assert.Equal(count, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<TimestampedSetDto> Generate(int n, DateTimeOffset from)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
yield return new TimestampedSetDto
|
|
||||||
(
|
|
||||||
from.AddSeconds(i),
|
|
||||||
new Dictionary<string, object>{
|
|
||||||
{"A", i },
|
|
||||||
{"B", i * 1.1 },
|
|
||||||
{"C", $"Any{i}" },
|
|
||||||
{"D", DateTimeOffset.Now},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,405 @@
|
|||||||
|
using DD.Persistence.Client;
|
||||||
|
using DD.Persistence.Client.Clients;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
|
using DD.Persistence.Database.Entity;
|
||||||
|
using DD.Persistence.Models;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace DD.Persistence.IntegrationTests.Controllers;
|
||||||
|
public class TimestampedValuesControllerTest : BaseIntegrationTest
|
||||||
|
{
|
||||||
|
private readonly ITimestampedValuesClient timestampedValuesClient;
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
|
private IEnumerable<Guid> discriminatorIds = [];
|
||||||
|
|
||||||
|
public TimestampedValuesControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
|
{
|
||||||
|
var refitClientFactory = scope.ServiceProvider
|
||||||
|
.GetRequiredService<IRefitClientFactory<IRefitTimestampedValuesClient>>();
|
||||||
|
var logger = scope.ServiceProvider.GetRequiredService<ILogger<TimestampedValuesClient>>();
|
||||||
|
|
||||||
|
timestampedValuesClient = scope.ServiceProvider
|
||||||
|
.GetRequiredService<ITimestampedValuesClient>();
|
||||||
|
memoryCache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddRange_returns_success()
|
||||||
|
{
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
await AddRange(discriminatorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Get_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.Get(discriminatorId, null, null, 0, 1, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Null(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
|
||||||
|
public async Task Get_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var timestampBegin = DateTimeOffset.UtcNow.AddDays(-1);
|
||||||
|
var columnNames = new List<string>() { "A", "C" };
|
||||||
|
var skip = 5;
|
||||||
|
var take = 5;
|
||||||
|
|
||||||
|
var dtos = await AddRange(discriminatorId);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.Get(discriminatorId, timestampBegin, columnNames, skip, take, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.NotEmpty(response);
|
||||||
|
|
||||||
|
var actualCount = response.Count();
|
||||||
|
Assert.Equal(take, actualCount);
|
||||||
|
|
||||||
|
var actualColumnNames = response.SelectMany(e => e.Values.Keys).Distinct().ToList();
|
||||||
|
Assert.Equal(columnNames, actualColumnNames);
|
||||||
|
|
||||||
|
var expectedValueKind = JsonValueKind.Number;
|
||||||
|
var actualValueKind = ((JsonElement) response.First().Values["A"]).ValueKind;
|
||||||
|
Assert.Equal(expectedValueKind, actualValueKind);
|
||||||
|
|
||||||
|
expectedValueKind = JsonValueKind.String;
|
||||||
|
actualValueKind = ((JsonElement)response.First().Values["C"]).ValueKind;
|
||||||
|
Assert.Equal(expectedValueKind, actualValueKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetGtDate_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var timestampBegin = DateTimeOffset.UtcNow.AddDays(-1);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetGtDate(discriminatorId, timestampBegin, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Null(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetGtDate_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var dtos = await AddRange(discriminatorId);
|
||||||
|
var timestampBegin = DateTimeOffset.UtcNow.AddSeconds(-5);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetGtDate(discriminatorId, timestampBegin, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.NotEmpty(response);
|
||||||
|
|
||||||
|
var expectedCount = dtos.Count(dto => dto.Timestamp.ToUniversalTime() > timestampBegin);
|
||||||
|
var actualCount = response.Count();
|
||||||
|
Assert.Equal(expectedCount, actualCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetFirst_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var take = 1;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetFirst(discriminatorId, take, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Null(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetFirst_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var dtos = await AddRange(discriminatorId);
|
||||||
|
var take = 1;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetFirst(discriminatorId, take, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.NotEmpty(response);
|
||||||
|
|
||||||
|
var expectedTimestampString = dtos
|
||||||
|
.OrderBy(dto => dto.Timestamp)
|
||||||
|
.First().Timestamp
|
||||||
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
|
var actualTimestampString = response
|
||||||
|
.First().Timestamp
|
||||||
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
|
Assert.Equal(expectedTimestampString, actualTimestampString);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetLast_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var take = 1;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetLast(discriminatorId, take, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Null(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetLast_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var dtos = await AddRange(discriminatorId);
|
||||||
|
var take = 1;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetLast(discriminatorId, take, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.NotEmpty(response);
|
||||||
|
|
||||||
|
var expectedTimestampString = dtos
|
||||||
|
.OrderByDescending(dto => dto.Timestamp)
|
||||||
|
.First().Timestamp
|
||||||
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
|
var actualTimestampString = response
|
||||||
|
.First().Timestamp
|
||||||
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
|
Assert.Equal(expectedTimestampString, actualTimestampString);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetResampledData_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var timestampBegin = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetResampledData(discriminatorId, timestampBegin);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Null(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetResampledData_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var count = 2048;
|
||||||
|
var timestampBegin = DateTimeOffset.UtcNow;
|
||||||
|
var dtos = await AddRange(discriminatorId, count);
|
||||||
|
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetResampledData(discriminatorId, timestampBegin, count);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
Assert.NotEmpty(response);
|
||||||
|
|
||||||
|
var expectedCount = count / 2;
|
||||||
|
var actualCount = response.Count();
|
||||||
|
Assert.Equal(expectedCount, actualCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Count_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.Count(discriminatorId, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Equal(0, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Count_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var dtos = await AddRange(discriminatorId);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.Count(discriminatorId, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
var expectedCount = dtos.Count();
|
||||||
|
Assert.Equal(expectedCount, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetDatesRange_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetDatesRange(discriminatorId, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.Null(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetDatesRange_AfterSave_returns_success()
|
||||||
|
{
|
||||||
|
//arrange
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
var discriminatorId = Guid.NewGuid();
|
||||||
|
discriminatorIds.Append(discriminatorId);
|
||||||
|
|
||||||
|
var dtos = await AddRange(discriminatorId);
|
||||||
|
|
||||||
|
//act
|
||||||
|
var response = await timestampedValuesClient.GetDatesRange(discriminatorId, CancellationToken.None);
|
||||||
|
|
||||||
|
//assert
|
||||||
|
Assert.NotNull(response);
|
||||||
|
|
||||||
|
var expectedDateFromString = dtos
|
||||||
|
.OrderBy(dto => dto.Timestamp)
|
||||||
|
.First().Timestamp
|
||||||
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
|
var actualDateFromString = response.From
|
||||||
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
|
Assert.Equal(expectedDateFromString, actualDateFromString);
|
||||||
|
|
||||||
|
var expectedDateToString = dtos
|
||||||
|
.OrderByDescending(dto => dto.Timestamp)
|
||||||
|
.First().Timestamp
|
||||||
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
|
var actualDateToString = response.To
|
||||||
|
.ToUniversalTime()
|
||||||
|
.ToString();
|
||||||
|
Assert.Equal(expectedDateToString, actualDateToString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<TimestampedValuesDto>> AddRange(Guid discriminatorId, int countToCreate = 10)
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
IEnumerable<TimestampedValuesDto> generatedDtos = Generate(countToCreate, DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(7)));
|
||||||
|
|
||||||
|
// act
|
||||||
|
var response = await timestampedValuesClient.AddRange(discriminatorId, generatedDtos, CancellationToken.None);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.Equal(generatedDtos.Count(), response);
|
||||||
|
|
||||||
|
return generatedDtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TimestampedValuesDto> Generate(int countToCreate, DateTimeOffset from)
|
||||||
|
{
|
||||||
|
var result = new List<TimestampedValuesDto>();
|
||||||
|
for (int i = 0; i < countToCreate; i++)
|
||||||
|
{
|
||||||
|
var values = new Dictionary<string, object>()
|
||||||
|
{
|
||||||
|
{ "A", i },
|
||||||
|
{ "B", i * 1.1 },
|
||||||
|
{ "C", $"Any{i}" },
|
||||||
|
{ "D", DateTimeOffset.Now },
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new TimestampedValuesDto()
|
||||||
|
{
|
||||||
|
Timestamp = from.AddSeconds(i),
|
||||||
|
Values = values
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cleanup()
|
||||||
|
{
|
||||||
|
discriminatorIds = [];
|
||||||
|
dbContext.CleanupDbSet<TimestampedValues>();
|
||||||
|
dbContext.CleanupDbSet<DataScheme>();
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using DD.Persistence.Client;
|
||||||
|
using DD.Persistence.Client.Clients;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Interfaces.Refit;
|
||||||
using DD.Persistence.Database.Entity;
|
using DD.Persistence.Database.Entity;
|
||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
using System.Net;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
|
||||||
using DD.Persistence.Client;
|
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests.Controllers;
|
namespace DD.Persistence.IntegrationTests.Controllers;
|
||||||
public class WitsDataControllerTest : BaseIntegrationTest
|
public class WitsDataControllerTest : BaseIntegrationTest
|
||||||
@ -13,11 +15,12 @@ public class WitsDataControllerTest : BaseIntegrationTest
|
|||||||
|
|
||||||
public WitsDataControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public WitsDataControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
var scope = factory.Services.CreateScope();
|
var refitClientFactory = scope.ServiceProvider
|
||||||
var persistenceClientFactory = scope.ServiceProvider
|
.GetRequiredService<IRefitClientFactory<IRefitWitsDataClient>>();
|
||||||
.GetRequiredService<PersistenceClientFactory>();
|
var logger = scope.ServiceProvider.GetRequiredService<ILogger<WitsDataClient>>();
|
||||||
|
|
||||||
witsDataClient = persistenceClientFactory.GetWitsDataClient();
|
witsDataClient = scope.ServiceProvider
|
||||||
|
.GetRequiredService<IWitsDataClient>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
namespace DD.Persistence.IntegrationTests
|
using DD.Persistence.Client.Helpers;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace DD.Persistence.IntegrationTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Фабрика HTTP клиентов для интеграционных тестов
|
/// Фабрика HTTP клиентов для интеграционных тестов
|
||||||
@ -6,14 +9,19 @@
|
|||||||
public class TestHttpClientFactory : IHttpClientFactory
|
public class TestHttpClientFactory : IHttpClientFactory
|
||||||
{
|
{
|
||||||
private readonly WebAppFactoryFixture factory;
|
private readonly WebAppFactoryFixture factory;
|
||||||
|
private readonly IConfiguration configuration;
|
||||||
|
|
||||||
public TestHttpClientFactory(WebAppFactoryFixture factory)
|
public TestHttpClientFactory(WebAppFactoryFixture factory, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
public HttpClient CreateClient(string name)
|
public HttpClient CreateClient(string name)
|
||||||
{
|
{
|
||||||
return factory.CreateClient();
|
var client = factory.CreateClient();
|
||||||
|
client.Authorize(configuration);
|
||||||
|
|
||||||
|
return client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,9 @@ using DD.Persistence.Database.Model;
|
|||||||
using DD.Persistence.Database.Postgres;
|
using DD.Persistence.Database.Postgres;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
using DD.Persistence.App;
|
using DD.Persistence.App;
|
||||||
|
using DD.Persistence.Client.Helpers;
|
||||||
|
using DD.Persistence.Factories;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace DD.Persistence.IntegrationTests;
|
namespace DD.Persistence.IntegrationTests;
|
||||||
public class WebAppFactoryFixture : WebApplicationFactory<Program>
|
public class WebAppFactoryFixture : WebApplicationFactory<Program>
|
||||||
@ -40,12 +43,12 @@ public class WebAppFactoryFixture : WebApplicationFactory<Program>
|
|||||||
services.AddLogging(builder => builder.AddConsole());
|
services.AddLogging(builder => builder.AddConsole());
|
||||||
|
|
||||||
services.RemoveAll<IHttpClientFactory>();
|
services.RemoveAll<IHttpClientFactory>();
|
||||||
services.AddSingleton<IHttpClientFactory>(provider =>
|
services.AddSingleton<IHttpClientFactory>((provider) =>
|
||||||
{
|
{
|
||||||
return new TestHttpClientFactory(this);
|
return new TestHttpClientFactory(this, provider.GetRequiredService<IConfiguration>());
|
||||||
});
|
});
|
||||||
|
services.AddHttpClient();
|
||||||
services.AddSingleton<PersistenceClientFactory>();
|
services.AddPersistenceClients();
|
||||||
|
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
43
DD.Persistence.Models/DD.Persistence.Models.csproj
Normal file
43
DD.Persistence.Models/DD.Persistence.Models.csproj
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
|
||||||
|
<!--Генерация NuGet пакета при сборке-->
|
||||||
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
|
<!--Наименование-->
|
||||||
|
<Title>DD.Persistence.Models</Title>
|
||||||
|
<!--Версия пакета-->
|
||||||
|
<VersionPrefix>1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</VersionPrefix>
|
||||||
|
<!--Версия сборки-->
|
||||||
|
<AssemblyVersion>1.3.$([System.DateTime]::UtcNow.ToString(yyMM.ddHH))</AssemblyVersion>
|
||||||
|
<!--Id пакета-->
|
||||||
|
<PackageId>DD.Persistence.Models</PackageId>
|
||||||
|
|
||||||
|
<!--Автор-->
|
||||||
|
<Authors>Digital Drilling</Authors>
|
||||||
|
<!--Компания-->
|
||||||
|
<Company>Digital Drilling</Company>
|
||||||
|
<!--Описание-->
|
||||||
|
<Description>Пакет для получения dtos для работы с Persistence сервисом</Description>
|
||||||
|
|
||||||
|
<!--Url репозитория-->
|
||||||
|
<RepositoryUrl>https://git.ddrilling.ru/on.nemtina/persistence.git</RepositoryUrl>
|
||||||
|
<!--тип репозитория-->
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<!--Символы отладки-->
|
||||||
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
|
<!--Формат пакета с символами-->
|
||||||
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
|
<!--Путь к пакету-->
|
||||||
|
<PackageOutputPath>C:\Projects\Nuget\Persistence</PackageOutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.3.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
17
DD.Persistence.Models/DataSchemeDto.cs
Normal file
17
DD.Persistence.Models/DataSchemeDto.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace DD.Persistence.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Схема для набора данных
|
||||||
|
/// </summary>
|
||||||
|
public class DataSchemeDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Дискриминатор
|
||||||
|
/// </summary>
|
||||||
|
public Guid DiscriminatorId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Наименования полей
|
||||||
|
/// </summary>
|
||||||
|
public string[] PropNames { get; set; } = [];
|
||||||
|
}
|
@ -13,7 +13,7 @@ public class DataSourceSystemDto
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Наименование
|
/// Наименование
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Описание
|
/// Описание
|
@ -1,4 +1,4 @@
|
|||||||
namespace DD.Persistence.Models;
|
namespace DD.Persistence.Models.Common;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Диапазон дат
|
/// Диапазон дат
|
@ -1,12 +1,12 @@
|
|||||||
namespace DD.Persistence.Models;
|
namespace DD.Persistence.ModelsAbstractions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Интерфейс, описывающий временные данные
|
/// Интерфейс, описывающий временные данные
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITimeSeriesAbstractDto
|
public interface ITimestampAbstractDto
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// временная отметка
|
/// временная отметка
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DateTimeOffset Date { get; set; }
|
DateTimeOffset Timestamp { get; set; }
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace DD.Persistence.Models;
|
namespace DD.Persistence.ModelsAbstractions;
|
||||||
public interface IWithSectionPart
|
public interface IWithSectionPart
|
||||||
{
|
{
|
||||||
public double DepthStart { get; set; }
|
public double DepthStart { get; set; }
|
@ -1,4 +1,4 @@
|
|||||||
namespace DD.Persistence.Models;
|
namespace DD.Persistence.Models.Common;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Контейнер для поддержки постраничного просмотра таблиц
|
/// Контейнер для поддержки постраничного просмотра таблиц
|
@ -8,7 +8,7 @@ public class SetpointLogDto : SetpointValueDto
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Дата сохранения уставки
|
/// Дата сохранения уставки
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTimeOffset Created { get; set; }
|
public DateTimeOffset Timestamp { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ключ пользователя
|
/// Ключ пользователя
|
19
DD.Persistence.Models/TimestampedValuesDto.cs
Normal file
19
DD.Persistence.Models/TimestampedValuesDto.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using DD.Persistence.ModelsAbstractions;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Набор данных с отметкой времени
|
||||||
|
/// </summary>
|
||||||
|
public class TimestampedValuesDto : ITimestampAbstractDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Временная отметка
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset Timestamp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Набор данных
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, object> Values { get; set; } = [];
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||||
|
<PackageReference Include="Shouldly" Version="4.2.1" />
|
||||||
|
<PackageReference Include="Testcontainers" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Testcontainers.PostgreSql" Version="4.1.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.2" />
|
||||||
|
<PackageReference Include="xunit.extensibility.core" Version="2.9.2" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
|
||||||
|
<ProjectReference Include="..\DD.Persistence.Repository\DD.Persistence.Repository.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
32
DD.Persistence.Repository.Test/RepositoryTestFixture.cs
Normal file
32
DD.Persistence.Repository.Test/RepositoryTestFixture.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
using DD.Persistence.Database;
|
||||||
|
using DD.Persistence.Database.Model;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Testcontainers.PostgreSql;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Repository.Test;
|
||||||
|
|
||||||
|
public class RepositoryTestFixture : IAsyncLifetime
|
||||||
|
{
|
||||||
|
public readonly PostgreSqlContainer dbContainer = new PostgreSqlBuilder().Build();
|
||||||
|
|
||||||
|
|
||||||
|
public PersistencePostgresContext GetDbContext() => new(new DbContextOptionsBuilder<PersistencePostgresContext>()
|
||||||
|
.UseNpgsql(dbContainer.GetConnectionString()).Options);
|
||||||
|
|
||||||
|
public IMemoryCache GetMemoryCache() => new MemoryCache(new MemoryCacheOptions());
|
||||||
|
|
||||||
|
public virtual async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await dbContainer.StartAsync();
|
||||||
|
var forumDbContext = new PersistencePostgresContext(new DbContextOptionsBuilder<PersistencePostgresContext>()
|
||||||
|
.UseNpgsql(dbContainer.GetConnectionString()).Options);
|
||||||
|
|
||||||
|
await forumDbContext.Database.MigrateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisposeAsync() => await dbContainer.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
56
DD.Persistence.Repository.Test/SetpointRepositoryShould.cs
Normal file
56
DD.Persistence.Repository.Test/SetpointRepositoryShould.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using DD.Persistence.Database.Model;
|
||||||
|
using DD.Persistence.Repository.Repositories;
|
||||||
|
using Shouldly;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Repository.Test;
|
||||||
|
public class SetpointRepositoryShould : IClassFixture<RepositoryTestFixture>
|
||||||
|
{
|
||||||
|
private readonly RepositoryTestFixture fixture;
|
||||||
|
private readonly PersistencePostgresContext context;
|
||||||
|
private readonly SetpointRepository sut;
|
||||||
|
|
||||||
|
public SetpointRepositoryShould(RepositoryTestFixture fixture)
|
||||||
|
{
|
||||||
|
this.fixture = fixture;
|
||||||
|
context = fixture.GetDbContext();
|
||||||
|
sut = new SetpointRepository(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ReturnValueKindNumber()
|
||||||
|
{
|
||||||
|
var id = Guid.NewGuid();
|
||||||
|
var value = GetJsonFromObject(22);
|
||||||
|
await sut.Add(id, value, Guid.NewGuid(), CancellationToken.None);
|
||||||
|
|
||||||
|
var t = fixture.dbContainer.GetConnectionString();
|
||||||
|
//act
|
||||||
|
var result = await sut.GetCurrent([id], CancellationToken.None);
|
||||||
|
|
||||||
|
|
||||||
|
//assert
|
||||||
|
result.ShouldNotBeNull();
|
||||||
|
result.ShouldNotBeEmpty();
|
||||||
|
|
||||||
|
var setpoint = result.First();
|
||||||
|
|
||||||
|
setpoint.Value.ShouldNotBeNull();
|
||||||
|
setpoint
|
||||||
|
.Value.ShouldBeOfType<JsonElement>()
|
||||||
|
.ValueKind.ShouldBe(JsonValueKind.Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonElement GetJsonFromObject(object value)
|
||||||
|
{
|
||||||
|
var jsonString = JsonSerializer.Serialize(value);
|
||||||
|
var doc = JsonDocument.Parse(jsonString);
|
||||||
|
return doc.RootElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user