Изменение метода Get к TimestampedValues
All checks were successful
Unit tests / test (push) Successful in 47s

This commit is contained in:
Roman Efremov 2025-01-24 15:40:14 +05:00
parent a3605253d6
commit 8fd16512f3
11 changed files with 120 additions and 249 deletions

View File

@ -1,7 +1,6 @@
using DD.Persistence.Models; using DD.Persistence.Models;
using DD.Persistence.Models.Common; using DD.Persistence.Models.Common;
using DD.Persistence.Services.Interfaces; using DD.Persistence.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Net; using System.Net;
@ -11,15 +10,15 @@ namespace DD.Persistence.API.Controllers;
/// Хранение наборов данных с отметкой времени. /// Хранение наборов данных с отметкой времени.
/// </summary> /// </summary>
[ApiController] [ApiController]
[Authorize] //[Authorize]
[Route("api/[controller]")] [Route("api/[controller]")]
public class TimestampedValuesController : ControllerBase public class TimestampedValuesController : ControllerBase
{ {
private readonly ITimestampedValuesService timestampedValuesService; private readonly ITimestampedValuesService timestampedValuesService;
public TimestampedValuesController(ITimestampedValuesService service) public TimestampedValuesController(ITimestampedValuesService repository)
{ {
this.timestampedValuesService = service; this.timestampedValuesService = repository;
} }
/// <summary> /// <summary>
@ -41,26 +40,7 @@ public class TimestampedValuesController : ControllerBase
/// <summary> /// <summary>
/// Получение данных с фильтрацией. Значение фильтра null - отключен /// Получение данных с фильтрацией. Значение фильтра null - отключен
/// </summary> /// </summary>
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</param> /// <param name="discriminatorIds">Набор дискриминаторов</param>
/// <param name="timestampBegin">Фильтр позднее даты</param>
/// <param name="columnNames">Фильтр свойств набора</param>
/// <param name="skip"></param>
/// <param name="take"></param>
/// <param name="token"></param>
[HttpGet("{discriminatorId}")]
[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 timestampedValuesService.Get(discriminatorId, timestampBegin, columnNames, skip, take, token);
return result.Any() ? Ok(result) : NoContent();
}
/// <summary>
/// Получение данных с фильтрацией для нескольких систем. Значение фильтра null - отключен
/// </summary>
/// <param name="discriminatorIds">Набор дискриминаторов (идентификаторов)</param>
/// <param name="timestampBegin">Фильтр позднее даты</param> /// <param name="timestampBegin">Фильтр позднее даты</param>
/// <param name="columnNames">Фильтр свойств набора</param> /// <param name="columnNames">Фильтр свойств набора</param>
/// <param name="skip"></param> /// <param name="skip"></param>

View File

@ -19,22 +19,6 @@ public interface ITimestampedValuesClient : IDisposable
/// <param name="token"></param> /// <param name="token"></param>
Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token); 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>
/// Получить данные с фильтрацией для нескольких систем. Значение фильтра null - отключен /// Получить данные с фильтрацией для нескольких систем. Значение фильтра null - отключен
/// </summary> /// </summary>
@ -99,19 +83,6 @@ public interface ITimestampedValuesClient : IDisposable
/// <param name="token"></param> /// <param name="token"></param>
Task<DatesRangeDto?> GetDatesRange(Guid discriminatorId, CancellationToken token); 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>
/// ///
/// </summary> /// </summary>

View File

@ -17,17 +17,6 @@ public interface IRefitTimestampedValuesClient : IRefitClient, IDisposable
[Post($"{baseUrl}/{{discriminatorId}}")] [Post($"{baseUrl}/{{discriminatorId}}")]
Task<IApiResponse<int>> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token); Task<IApiResponse<int>> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token);
/// <summary>
/// Получение данных с фильтрацией для нескольких систем
/// </summary>
[Get($"{baseUrl}/{{discriminatorId}}")]
Task<IApiResponse<IEnumerable<TimestampedValuesDto>>> Get(Guid discriminatorId,
DateTimeOffset? timestampBegin,
[Query(CollectionFormat.Multi)] IEnumerable<string>? columnNames,
int skip,
int take,
CancellationToken token);
/// <summary> /// <summary>
/// Получение данных с фильтрацией /// Получение данных с фильтрацией
/// </summary> /// </summary>

View File

@ -31,14 +31,6 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
return result; 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/> /// <inheritdoc/>
public async Task<IEnumerable<TimestampedValuesDto>> Get(IEnumerable<Guid> discriminatorIds, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token) public async Task<IEnumerable<TimestampedValuesDto>> Get(IEnumerable<Guid> discriminatorIds, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
{ {
@ -101,15 +93,6 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
return result; 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/> /// <inheritdoc/>
public async Task<IEnumerable<T>> GetLast<T>(Guid idDiscriminator, int take, CancellationToken token) public async Task<IEnumerable<T>> GetLast<T>(Guid idDiscriminator, int take, CancellationToken token)
{ {

View File

@ -38,67 +38,67 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest
await AddRange(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] [Fact]
public async Task Get_returns_success() public async Task Get_returns_success()
{ {
//arrange //arrange
Cleanup(); 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 GetWithManyDiscriminators_returns_success()
{
//arrange
Cleanup();
var firstDiscriminatorId = Guid.NewGuid(); var firstDiscriminatorId = Guid.NewGuid();
discriminatorIds.Append(firstDiscriminatorId); discriminatorIds.Append(firstDiscriminatorId);
@ -113,7 +113,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest
} }
[Fact] [Fact]
public async Task GetWithManyDiscriminators_AfterSave_returns_success() public async Task Get_AfterSave_returns_success()
{ {
//arrange //arrange
Cleanup(); Cleanup();

View File

@ -3,7 +3,6 @@ using DD.Persistence.Models;
using DD.Persistence.Models.Common; using DD.Persistence.Models.Common;
using DD.Persistence.Repositories; using DD.Persistence.Repositories;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace DD.Persistence.Repository.Repositories; namespace DD.Persistence.Repository.Repositories;
public class TimestampedValuesRepository : ITimestampedValuesRepository public class TimestampedValuesRepository : ITimestampedValuesRepository
@ -38,37 +37,7 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository
return result; return result;
} }
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> Get(Guid discriminatorId, public async virtual Task<IDictionary<Guid, IEnumerable<(DateTimeOffset Timestamp, object[] Values)>>> Get(IEnumerable<Guid> discriminatorIds,
DateTimeOffset? timestampBegin,
IEnumerable<string>? columnNames,
int skip,
int take,
CancellationToken token)
{
var query = GetQueryReadOnly()
.Where(entity => entity.DiscriminatorId == discriminatorId);
// Фильтрация по дате
if (timestampBegin.HasValue)
{
query = ApplyGeTimestamp(query, timestampBegin.Value);
}
query = query
.OrderBy(item => item.Timestamp)
.Skip(skip)
.Take(take);
var entities = await query.ToArrayAsync(token);
var result = entities.Select(e => Tuple.Create(
e.Timestamp,
e.Values
));
return result;
}
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> Get(IEnumerable<Guid> discriminatorIds,
DateTimeOffset? timestampBegin, DateTimeOffset? timestampBegin,
IEnumerable<string>? columnNames, IEnumerable<string>? columnNames,
int skip, int skip,
@ -84,28 +53,28 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository
query = ApplyGeTimestamp(query, timestampBegin.Value); query = ApplyGeTimestamp(query, timestampBegin.Value);
} }
query = query // Группировка отсортированных значений по DiscriminatorId
.OrderBy(item => item.Timestamp) var groupQuery = query
.Skip(skip) .GroupBy(e => e.DiscriminatorId)
.Take(take); .Select(g => KeyValuePair.Create(g.Key, g.OrderBy(i => i.Timestamp).Skip(skip).Take(take)));
var entities = await query.ToArrayAsync(token); var entities = await groupQuery.ToArrayAsync(token);
var result = entities.Select(e => Tuple.Create( var result = entities.ToDictionary(k => k.Key, v => v.Value.Select(e => (
e.Timestamp, e.Timestamp,
e.Values e.Values
)); )));
return result; return result;
} }
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetFirst(Guid discriminatorId, int takeCount, CancellationToken token) public async virtual Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetFirst(Guid discriminatorId, int takeCount, CancellationToken token)
{ {
var query = GetQueryReadOnly() var query = GetQueryReadOnly()
.OrderBy(e => e.Timestamp) .OrderBy(e => e.Timestamp)
.Take(takeCount); .Take(takeCount);
var entities = await query.ToArrayAsync(token); var entities = await query.ToArrayAsync(token);
var result = entities.Select(e => Tuple.Create( var result = entities.Select(e => (
e.Timestamp, e.Timestamp,
e.Values e.Values
)); ));
@ -113,14 +82,14 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository
return result; return result;
} }
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetLast(Guid discriminatorId, int takeCount, CancellationToken token) public async virtual Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetLast(Guid discriminatorId, int takeCount, CancellationToken token)
{ {
var query = GetQueryReadOnly() var query = GetQueryReadOnly()
.OrderByDescending(e => e.Timestamp) .OrderByDescending(e => e.Timestamp)
.Take(takeCount); .Take(takeCount);
var entities = await query.ToArrayAsync(token); var entities = await query.ToArrayAsync(token);
var result = entities.Select(e => Tuple.Create( var result = entities.Select(e => (
e.Timestamp, e.Timestamp,
e.Values e.Values
)); ));
@ -129,7 +98,7 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository
} }
// ToDo: прореживание должно осуществляться до материализации // ToDo: прореживание должно осуществляться до материализации
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetResampledData( public async virtual Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetResampledData(
Guid discriminatorId, Guid discriminatorId,
DateTimeOffset dateBegin, DateTimeOffset dateBegin,
double intervalSec = 600d, double intervalSec = 600d,
@ -150,13 +119,13 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository
return result; return result;
} }
public async virtual Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token) public async virtual Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token)
{ {
var query = GetQueryReadOnly() var query = GetQueryReadOnly()
.Where(e => e.Timestamp > timestampBegin); .Where(e => e.Timestamp > timestampBegin);
var entities = await query.ToArrayAsync(token); var entities = await query.ToArrayAsync(token);
var result = entities.Select(e => Tuple.Create( var result = entities.Select(e => (
e.Timestamp, e.Timestamp,
e.Values e.Values
)); ));

View File

@ -28,14 +28,14 @@ public interface ITimestampedValuesRepository : ISyncRepository, ITimeSeriesBase
/// <summary> /// <summary>
/// Получение данных с фильтрацией. Значение фильтра null - отключен /// Получение данных с фильтрацией. Значение фильтра null - отключен
/// </summary> /// </summary>
/// <param name="idDiscriminator">Дискриминатор (идентификатор) набора</param> /// <param name="idDiscriminators">Набор дискриминаторов (идентификаторов)</param>
/// <param name="geTimestamp">Фильтр позднее даты</param> /// <param name="geTimestamp">Фильтр позднее даты</param>
/// <param name="columnNames">Фильтр свойств набора. Можно запросить только некоторые свойства из набора</param> /// <param name="columnNames">Фильтр свойств набора. Можно запросить только некоторые свойства из набора</param>
/// <param name="skip"></param> /// <param name="skip"></param>
/// <param name="take"></param> /// <param name="take"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> Get(Guid idDiscriminator, Task<IDictionary<Guid, IEnumerable<(DateTimeOffset Timestamp, object[] Values)>>> Get(IEnumerable<Guid> idDiscriminators,
DateTimeOffset? geTimestamp, DateTimeOffset? geTimestamp,
IEnumerable<string>? columnNames, IEnumerable<string>? columnNames,
int skip, int skip,
@ -49,7 +49,7 @@ public interface ITimestampedValuesRepository : ISyncRepository, ITimeSeriesBase
/// <param name="takeCount">Количество</param> /// <param name="takeCount">Количество</param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetFirst(Guid discriminatorId, int takeCount, CancellationToken token); Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetFirst(Guid discriminatorId, int takeCount, CancellationToken token);
/// <summary> /// <summary>
/// Получение данных с конца /// Получение данных с конца
@ -58,5 +58,5 @@ public interface ITimestampedValuesRepository : ISyncRepository, ITimeSeriesBase
/// <param name="takeCount">Количество</param> /// <param name="takeCount">Количество</param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetLast(Guid discriminatorId, int takeCount, CancellationToken token); Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetLast(Guid discriminatorId, int takeCount, CancellationToken token);
} }

View File

@ -15,7 +15,7 @@ public interface ISyncRepository // ToDo: исчерпывающая абстр
/// <param name="dateBegin">дата начала</param> /// <param name="dateBegin">дата начала</param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetGtDate(Guid discriminatorId, DateTimeOffset dateBegin, CancellationToken token); Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetGtDate(Guid discriminatorId, DateTimeOffset dateBegin, CancellationToken token);
/// <summary> /// <summary>

View File

@ -16,7 +16,7 @@ public interface ITimeSeriesBaseRepository // ToDo: исчерпывающая
/// <param name="approxPointsCount"></param> /// <param name="approxPointsCount"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<Tuple<DateTimeOffset, object[]>>> GetResampledData( Task<IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> GetResampledData(
Guid discriminatorId, Guid discriminatorId,
DateTimeOffset dateBegin, DateTimeOffset dateBegin,
double intervalSec = 600d, double intervalSec = 600d,

View File

@ -25,19 +25,6 @@ public interface ITimestampedValuesService
/// <returns></returns> /// <returns></returns>
Task<int> Count(Guid discriminatorId, CancellationToken token); Task<int> Count(Guid discriminatorId, CancellationToken token);
/// <summary>
/// Получение данных с фильтрацией. Значение фильтра null - отключен
/// </summary>
/// <param name="discriminatorId">Дискриминатор (идентификатор) набора</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<TimestampedValuesDto>> Get(Guid discriminatorId, DateTimeOffset? geTimestamp,
IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
/// <summary> /// <summary>
/// Получение данных с фильтрацией для нескольких систем. Значение фильтра null - отключен /// Получение данных с фильтрацией для нескольких систем. Значение фильтра null - отключен
/// </summary> /// </summary>

View File

@ -34,31 +34,12 @@ public class TimestampedValuesService : ITimestampedValuesService
return result; 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 timestampedValuesRepository.Get(discriminatorId, geTimestamp, columnNames, skip, take, token);
var dtos = await Materialize(discriminatorId, result, token);
if (!columnNames.IsNullOrEmpty())
{
dtos = ReduceSetColumnsByNames(dtos, columnNames!);
}
return dtos;
}
/// <inheritdoc/> /// <inheritdoc/>
public async Task<IEnumerable<TimestampedValuesDto>> Get(IEnumerable<Guid> discriminatorIds, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token) public async Task<IEnumerable<TimestampedValuesDto>> Get(IEnumerable<Guid> discriminatorIds, DateTimeOffset? geTimestamp, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
{ {
var result = await timestampedValuesRepository.Get(discriminatorIds, geTimestamp, columnNames, skip, take, token); var result = await timestampedValuesRepository.Get(discriminatorIds, geTimestamp, columnNames, skip, take, token);
List<TimestampedValuesDto> dtos = []; var dtos = await Materialize(result, token);
discriminatorIds.ForEach(async discriminatorId => {
var materializeDtos = await Materialize(discriminatorId, result, token);
dtos.AddRange(materializeDtos);
});
if (!columnNames.IsNullOrEmpty()) if (!columnNames.IsNullOrEmpty())
{ {
@ -73,7 +54,9 @@ public class TimestampedValuesService : ITimestampedValuesService
{ {
var result = await timestampedValuesRepository.GetFirst(discriminatorId, takeCount, token); var result = await timestampedValuesRepository.GetFirst(discriminatorId, takeCount, token);
var dtos = await Materialize(discriminatorId, result, token); var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) }
.ToDictionary();
var dtos = await Materialize(resultToMaterialize, token);
return dtos; return dtos;
} }
@ -83,7 +66,9 @@ public class TimestampedValuesService : ITimestampedValuesService
{ {
var result = await timestampedValuesRepository.GetLast(discriminatorId, takeCount, token); var result = await timestampedValuesRepository.GetLast(discriminatorId, takeCount, token);
var dtos = await Materialize(discriminatorId, result, token); var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) }
.ToDictionary();
var dtos = await Materialize(resultToMaterialize, token);
return dtos; return dtos;
} }
@ -98,7 +83,9 @@ public class TimestampedValuesService : ITimestampedValuesService
{ {
var result = await timestampedValuesRepository.GetResampledData(discriminatorId, beginTimestamp, intervalSec, approxPointsCount, token); var result = await timestampedValuesRepository.GetResampledData(discriminatorId, beginTimestamp, intervalSec, approxPointsCount, token);
var dtos = await Materialize(discriminatorId, result, token); var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) }
.ToDictionary();
var dtos = await Materialize(resultToMaterialize, token);
return dtos; return dtos;
} }
@ -108,7 +95,9 @@ public class TimestampedValuesService : ITimestampedValuesService
{ {
var result = await timestampedValuesRepository.GetGtDate(discriminatorId, beginTimestamp, token); var result = await timestampedValuesRepository.GetGtDate(discriminatorId, beginTimestamp, token);
var dtos = await Materialize(discriminatorId, result, token); var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) }
.ToDictionary();
var dtos = await Materialize(resultToMaterialize, token);
return dtos; return dtos;
} }
@ -132,35 +121,38 @@ public class TimestampedValuesService : ITimestampedValuesService
/// <summary> /// <summary>
/// Преобразовать результат запроса в набор dto /// Преобразовать результат запроса в набор dto
/// </summary> /// </summary>
/// <param name="dataSchemeId"></param>
/// <param name="queryResult"></param> /// <param name="queryResult"></param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
private async Task<IEnumerable<TimestampedValuesDto>> Materialize(Guid dataSchemeId, IEnumerable<Tuple<DateTimeOffset, object[]>> queryResult, CancellationToken token) private async Task<IEnumerable<TimestampedValuesDto>> Materialize(IDictionary<Guid, IEnumerable<(DateTimeOffset Timestamp, object[] Values)>> queryResult, CancellationToken token)
{ {
var dataScheme = await dataSchemeRepository.Get(dataSchemeId, token); IEnumerable<TimestampedValuesDto> result = [];
if (dataScheme is null) foreach (var keyValuePair in queryResult)
{ {
return []; var dataScheme = await dataSchemeRepository.Get(keyValuePair.Key, token);
if (dataScheme is null)
{
continue;
}
foreach (var tuple in keyValuePair.Value)
{
var identity = dataScheme!.PropNames;
var indexedIdentity = identity
.Select((value, index) => new { index, value });
var dto = new TimestampedValuesDto()
{
Timestamp = tuple.Timestamp.ToUniversalTime(),
Values = indexedIdentity
.ToDictionary(x => x.value, x => tuple.Values[x.index])
};
result = result.Append(dto);
}
} }
var dtos = queryResult.Select(entity => return result;
{
var dto = new TimestampedValuesDto()
{
Timestamp = entity.Item1.ToUniversalTime()
};
var identity = dataScheme!.PropNames;
var indexedIdentity = identity
.Select((value, index) => new { index, value });
dto.Values = indexedIdentity
.ToDictionary(x => x.value, x => entity.Item2[x.index]);
return dto;
});
return dtos;
} }
/// <summary> /// <summary>