@ -1,4 +1,4 @@
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
using DD.Persistence.Models.Common;
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients.Interfaces;
|
namespace DD.Persistence.Client.Clients.Interfaces;
|
||||||
@ -37,18 +37,6 @@ public interface ITimestampedValuesClient : IDisposable
|
|||||||
int take,
|
int take,
|
||||||
CancellationToken token);
|
CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить данные с фильтрацией для нескольких систем. Значение фильтра null - отключен
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="discriminatorId"></param>
|
|
||||||
/// <param name="geTimestamp"></param>
|
|
||||||
/// <param name="filterTree"></param>
|
|
||||||
/// <param name="columnNames">Фильтр свойств набора</param>
|
|
||||||
/// <param name="skip"></param>
|
|
||||||
/// <param name="take"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
Task<IEnumerable<T>> Get<T>(Guid discriminatorId, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить данные, начиная с заданной отметки времени
|
/// Получить данные, начиная с заданной отметки времени
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -97,13 +85,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="take"></param>
|
|
||||||
/// <param name="token"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<IEnumerable<T>> GetLast<T>(Guid idDiscriminator, int take, CancellationToken token);
|
|
||||||
}
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
namespace DD.Persistence.Client.Clients.Mapping.Abstractions;
|
||||||
|
internal interface IMapperStorage
|
||||||
|
{
|
||||||
|
TimestampedSetMapper GetMapper<T>(Guid idDiscriminator);
|
||||||
|
TimestampedSetMapper? GetMapper(Guid idDiscriminator);
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients.Mapping.Abstractions;
|
||||||
|
public interface ISetpointMappingClient : ISetpointClient
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients.Mapping.Abstractions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Маппинг - обертка для клиента по работе с данными
|
||||||
|
/// </summary>
|
||||||
|
public interface ITimestampedMappingClient : ITimestampedValuesClient
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Получить данные с преобразованием к заданному типу
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorId"></param>
|
||||||
|
/// <param name="geTimestamp"></param>
|
||||||
|
/// <param name="columnNames">Фильтр свойств набора</param>
|
||||||
|
/// <param name="filterTree"></param>
|
||||||
|
/// <param name="skip"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
Task<IEnumerable<T>> GetMapped<T>(Guid discriminatorId, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить набор данных, преобразованных к соответствующим типам из заданного конфига
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="discriminatorIds"></param>
|
||||||
|
/// <param name="timestampBegin"></param>
|
||||||
|
/// <param name="filterTree"></param>
|
||||||
|
/// <param name="columnNames"></param>
|
||||||
|
/// <param name="skip"></param>
|
||||||
|
/// <param name="take"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IDictionary<Guid, IEnumerable<object>>> GetMultiMapped(IEnumerable<Guid> discriminatorIds, DateTimeOffset? timestampBegin, string? filterTree, 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>> GetLastMapped<T>(Guid idDiscriminator, int take, CancellationToken token);
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Mapping.Abstractions;
|
||||||
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
using DD.Persistence.Models.Configurations;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients.Mapping.Clients;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public class SetpointMappingClient : ISetpointMappingClient
|
||||||
|
{
|
||||||
|
private readonly ISetpointClient setpointClient;
|
||||||
|
private readonly MappingConfig mappingConfigs;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public SetpointMappingClient(ISetpointClient setpointClient, MappingConfig mappingConfigs)
|
||||||
|
{
|
||||||
|
this.setpointClient = setpointClient;
|
||||||
|
this.mappingConfigs = mappingConfigs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<SetpointValueDto>> GetCurrent(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||||
|
=> (await setpointClient.GetCurrent(setpointKeys, token))
|
||||||
|
.Select(x => new SetpointValueDto
|
||||||
|
{
|
||||||
|
Key = x.Key,
|
||||||
|
Value = DeserializeValue(x.Key, (JsonElement)x.Value)
|
||||||
|
});
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<Dictionary<Guid, object>> GetCurrentDictionary(IEnumerable<Guid> setpointConfigs, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = (await setpointClient.GetCurrent(setpointConfigs, token))
|
||||||
|
.ToDictionary(x => x.Key, x => DeserializeValue(x.Key, (JsonElement)x.Value));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await setpointClient.GetHistory(setpointKeys, historyMoment, token);
|
||||||
|
|
||||||
|
foreach (var dto in result)
|
||||||
|
dto.Value = DeserializeValue(dto.Key, (JsonElement)dto.Value);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<Dictionary<Guid, IEnumerable<SetpointLogDto>>> GetLog(IEnumerable<Guid> setpointKeys, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await setpointClient.GetLog(setpointKeys, token);
|
||||||
|
|||||||
|
|
||||||
|
foreach (var item in result)
|
||||||
|
DeserializeList(result[item.Key]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<SetpointLogDto>> GetPart(DateTimeOffset dateBegin, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var result = await setpointClient.GetPart(dateBegin, take, token);
|
||||||
|
|
||||||
|
DeserializeList(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
on.nemtina
commented
добавить GC.SuppressFinalize(this); добавить GC.SuppressFinalize(this);
|
|||||||
|
public async Task Add(Guid setpointKey, object newValue, CancellationToken token)
|
||||||
|
=> await setpointClient.Add(setpointKey, newValue, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<DatesRangeDto> GetDatesRangeAsync(CancellationToken token)
|
||||||
|
=> await setpointClient.GetDatesRangeAsync(token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
setpointClient.Dispose();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private object DeserializeValue(Guid key, JsonElement value)
|
||||||
|
{
|
||||||
|
if (mappingConfigs.TryGetValue(key, out var type))
|
||||||
|
return value.Deserialize(type)!;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
private void DeserializeList(IEnumerable<SetpointLogDto>? result)
|
||||||
|
{
|
||||||
|
if (result is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var log in result)
|
||||||
|
log.Value = DeserializeValue(log.Key, (JsonElement)log.Value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Mapping.Abstractions;
|
||||||
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Common;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients.Mapping.Clients;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
internal class TimestampedMappingClient : ITimestampedMappingClient
|
||||||
on.nemtina
commented
Нужно сделать отдельный сервис, который отвечает за кеширование маппингов, и зарегистрировать его в DI. Нужно сделать отдельный сервис, который отвечает за кеширование маппингов, и зарегистрировать его в DI.
|
|||||||
|
{
|
||||||
|
private readonly ITimestampedValuesClient client;
|
||||||
|
private readonly IMapperStorage mapperStorage;
|
||||||
|
|
||||||
|
public TimestampedMappingClient(ITimestampedValuesClient client, IMapperStorage mapperStorage)
|
||||||
|
{
|
||||||
|
this.client = client;
|
||||||
|
this.mapperStorage = mapperStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<T>> GetMapped<T>(Guid discriminatorId, DateTimeOffset? geTimestamp,
|
||||||
|
string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var data = await Get([discriminatorId], geTimestamp, filterTree, columnNames, skip, take, token);
|
||||||
|
var mapper = mapperStorage.GetMapper<T>(discriminatorId);
|
||||||
|
|
||||||
|
var mappedDtos = data.Select(mapper.DeserializeTimeStampedData).OfType<T>();
|
||||||
|
|
||||||
|
return mappedDtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<T>> GetLastMapped<T>(Guid idDiscriminator, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var data = await GetLast(idDiscriminator, take, token);
|
||||||
|
var mapper = mapperStorage.GetMapper<T>(idDiscriminator);
|
||||||
|
|
||||||
|
var mappedDtos = data.Select(mapper.DeserializeTimeStampedData).OfType<T>();
|
||||||
|
|
||||||
|
return mappedDtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IDictionary<Guid, IEnumerable<object>>> GetMultiMapped(IEnumerable<Guid> discriminatorIds, DateTimeOffset? geTimestamp,
|
||||||
|
string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||||
|
{
|
||||||
|
var data = await client.Get(discriminatorIds, geTimestamp, filterTree, columnNames, skip, take, token);
|
||||||
|
|
||||||
|
var result = discriminatorIds
|
||||||
|
.ToDictionary(discriminatorId => discriminatorId, discriminatorId =>
|
||||||
|
{
|
||||||
|
var mapper = mapperStorage.GetMapper(discriminatorId);
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(mapper);
|
||||||
|
|
||||||
|
var mappedDtos = data
|
||||||
|
.Where(e => e.DiscriminatorId == discriminatorId)
|
||||||
|
.Select(mapper.DeserializeTimeStampedData);
|
||||||
|
|
||||||
|
return mappedDtos;
|
||||||
on.nemtina
commented
Желательно комментарии стереть Желательно комментарии стереть
|
|||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> dtos, CancellationToken token)
|
||||||
|
=> await client.AddRange(discriminatorId, dtos, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<int> Count(Guid discriminatorId, CancellationToken token)
|
||||||
|
=> await client.Count(discriminatorId, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> Get(IEnumerable<Guid> discriminatorIds, DateTimeOffset? timestampBegin,
|
||||||
|
string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
||||||
|
=> await client.Get(discriminatorIds, timestampBegin, filterTree, columnNames, skip, take, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<DatesRangeDto?> GetDatesRange(Guid discriminatorId, CancellationToken token)
|
||||||
|
=> await client.GetDatesRange(discriminatorId, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> GetFirst(Guid discriminatorId, int take, CancellationToken token)
|
||||||
|
=> await client.GetFirst(discriminatorId, take, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token)
|
||||||
|
=> await client.GetGtDate(discriminatorId, timestampBegin, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> GetLast(Guid discriminatorId, int take, CancellationToken token)
|
||||||
|
=> await client.GetLast(discriminatorId, take, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<TimestampedValuesDto>> GetResampledData(Guid discriminatorId, DateTimeOffset timestampBegin, double intervalSec = 600, int approxPointsCount = 1024, CancellationToken token = default)
|
||||||
|
=> await client.GetResampledData(discriminatorId, timestampBegin, intervalSec, approxPointsCount, token);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
client.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
33
DD.Persistence.Client/Clients/Mapping/MapperStorage.cs
Normal file
33
DD.Persistence.Client/Clients/Mapping/MapperStorage.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Mapping.Abstractions;
|
||||||
|
using DD.Persistence.Models.Configurations;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Client.Clients.Mapping;
|
||||||
|
internal class MapperStorage : IMapperStorage
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<Guid, TimestampedSetMapper> mapperCache = new();
|
||||||
|
private readonly MappingConfig mappingConfigs;
|
||||||
|
private readonly ILogger<TimestampedSetMapper> logger;
|
||||||
|
|
||||||
|
public MapperStorage(MappingConfig mappingConfigs, ILogger<TimestampedSetMapper> logger)
|
||||||
|
{
|
||||||
|
this.mappingConfigs = mappingConfigs;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public TimestampedSetMapper? GetMapper(Guid idDiscriminator)
|
||||||
|
{
|
||||||
|
if (mappingConfigs.TryGetValue(idDiscriminator, out var type))
|
||||||
|
return mapperCache.GetOrAdd(idDiscriminator, name => new TimestampedSetMapper(idDiscriminator, type, logger));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimestampedSetMapper GetMapper<T>(Guid idDiscriminator)
|
||||||
|
{
|
||||||
|
return mapperCache.GetOrAdd(idDiscriminator, name => new TimestampedSetMapper(idDiscriminator, typeof(T), logger));
|
||||||
|
}
|
||||||
|
}
|
@ -1,65 +1,62 @@
|
|||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace DD.Persistence.Client;
|
namespace DD.Persistence.Client.Clients.Mapping;
|
||||||
|
|
||||||
internal abstract class TimestampedSetMapperBase
|
internal class TimestampedSetMapper
|
||||||
{
|
{
|
||||||
public abstract object Map(TimestampedValuesDto data);
|
private readonly Type entityType;
|
||||||
|
private readonly ILogger<TimestampedSetMapper> logger;
|
||||||
|
|
||||||
}
|
|
||||||
internal class TimestampedSetMapper<T> : TimestampedSetMapperBase
|
|
||||||
{
|
|
||||||
private readonly Type entityType = typeof(T);
|
|
||||||
public Guid IdDiscriminator { get; }
|
public Guid IdDiscriminator { get; }
|
||||||
private readonly ConcurrentDictionary<string, PropertyInfo?> PropertyCache = new();
|
private readonly ConcurrentDictionary<string, PropertyInfo?> PropertyCache = new();
|
||||||
|
|
||||||
public TimestampedSetMapper(Guid idDiscriminator)
|
public TimestampedSetMapper(Guid idDiscriminator, Type entityType, ILogger<TimestampedSetMapper> logger)
|
||||||
{
|
{
|
||||||
IdDiscriminator = idDiscriminator;
|
IdDiscriminator = idDiscriminator;
|
||||||
|
this.entityType = entityType;
|
||||||
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object Map(TimestampedValuesDto data)
|
public object DeserializeTimeStampedData(TimestampedValuesDto data)
|
||||||
{
|
{
|
||||||
return DeserializeTimeStampedData(data)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T DeserializeTimeStampedData(TimestampedValuesDto data)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (entityType.IsValueType)
|
if (entityType.IsValueType)
|
||||||
return MapStruct(data);
|
return MapStruct(data);
|
||||||
else
|
|
||||||
return MapClass(data);
|
return MapClass(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private T MapClass(TimestampedValuesDto data)
|
private object MapClass(TimestampedValuesDto data)
|
||||||
{
|
{
|
||||||
var entity = (T)RuntimeHelpers.GetUninitializedObject(typeof(T));
|
var entity = RuntimeHelpers.GetUninitializedObject(entityType);
|
||||||
foreach (var (propertyName, value) in data.Values)
|
foreach (var (propertyName, value) in data.Values)
|
||||||
{
|
{
|
||||||
if (value is JsonElement jsonElement)
|
if (value is JsonElement jsonElement)
|
||||||
SetPropertyValueFromJson(ref entity, propertyName, jsonElement);
|
SetPropertyValueFromJson(ref entity, propertyName, jsonElement);
|
||||||
}
|
}
|
||||||
SetPropertyValue(ref entity, "Timestamp", data.Timestamp);
|
SetPropertyValue(ref entity, nameof(TimestampedValuesDto.Timestamp), data.Timestamp);
|
||||||
|
SetPropertyValue(ref entity, nameof(TimestampedValuesDto.DiscriminatorId), data.DiscriminatorId);
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private T MapStruct(TimestampedValuesDto data)
|
private object MapStruct(TimestampedValuesDto data)
|
||||||
{
|
{
|
||||||
var entity = Activator.CreateInstance<T>();
|
var entity = Activator.CreateInstance(entityType);
|
||||||
object boxedEntity = entity!;
|
object boxedEntity = entity!;
|
||||||
foreach (var (propertyName, value) in data.Values)
|
foreach (var (propertyName, value) in data.Values)
|
||||||
{
|
{
|
||||||
if (value is JsonElement jsonElement)
|
if (value is JsonElement jsonElement)
|
||||||
SetPropertyValueForStructFromJson(ref boxedEntity, propertyName, jsonElement);
|
SetPropertyValueForStructFromJson(ref boxedEntity, propertyName, jsonElement);
|
||||||
}
|
}
|
||||||
SetPropertyValueForStruct(ref boxedEntity, "Timestamp", data.Timestamp);
|
SetPropertyValueForStruct(ref boxedEntity, nameof(TimestampedValuesDto.Timestamp), data.Timestamp);
|
||||||
|
SetPropertyValueForStruct(ref boxedEntity, nameof(TimestampedValuesDto.DiscriminatorId), data.DiscriminatorId);
|
||||||
|
|
||||||
return (T)boxedEntity;
|
return boxedEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetPropertyValueForStructFromJson(ref object entity, string propertyName, JsonElement element)
|
private void SetPropertyValueForStructFromJson(ref object entity, string propertyName, JsonElement element)
|
||||||
@ -75,6 +72,7 @@ internal class TimestampedSetMapper<T> : TimestampedSetMapperBase
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
logger.LogError(ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void SetPropertyValueForStruct(ref object entity, string propertyName, object value)
|
private void SetPropertyValueForStruct(ref object entity, string propertyName, object value)
|
||||||
@ -90,11 +88,12 @@ internal class TimestampedSetMapper<T> : TimestampedSetMapperBase
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
logger.LogError(ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void SetPropertyValueFromJson(ref T entity, string propertyName, JsonElement jsonElement)
|
private void SetPropertyValueFromJson(ref object entity, string propertyName, JsonElement jsonElement)
|
||||||
{
|
{
|
||||||
var property = GetPropertyInfo(propertyName);
|
var property = GetPropertyInfo(propertyName);
|
||||||
on.nemtina
commented
Тут внутри блока Exception пусто, наверное, нужна какая-то обработка? Тут внутри блока Exception пусто, наверное, нужна какая-то обработка?
|
|||||||
|
|
||||||
@ -108,11 +107,11 @@ internal class TimestampedSetMapper<T> : TimestampedSetMapperBase
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
logger.LogError(ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetPropertyValue(ref T entity, string propertyName, object value)
|
private void SetPropertyValue(ref object entity, string propertyName, object value)
|
||||||
{
|
{
|
||||||
var property = GetPropertyInfo(propertyName);
|
var property = GetPropertyInfo(propertyName);
|
||||||
if (property is null)
|
if (property is null)
|
||||||
@ -125,6 +124,7 @@ internal class TimestampedSetMapper<T> : TimestampedSetMapperBase
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
logger.LogError(ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,9 +3,6 @@ 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;
|
using DD.Persistence.Models.Common;
|
||||||
|
|
||||||
namespace DD.Persistence.Client.Clients;
|
namespace DD.Persistence.Client.Clients;
|
||||||
@ -13,15 +10,12 @@ 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(
|
public SetpointClient(
|
||||||
IRefitClientFactory<IRefitSetpointClient> refitSetpointClientFactory,
|
IRefitClientFactory<IRefitSetpointClient> refitSetpointClientFactory,
|
||||||
ISetpointConfigStorage setpointConfigStorage,
|
|
||||||
ILogger<SetpointClient> logger) : base(logger)
|
ILogger<SetpointClient> logger) : base(logger)
|
||||||
{
|
{
|
||||||
this.refitSetpointClient = refitSetpointClientFactory.Create();
|
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)
|
||||||
@ -31,7 +25,7 @@ public class SetpointClient : BaseClient, ISetpointClient
|
|||||||
|
|
||||||
return result!.Select(x => new SetpointValueDto {
|
return result!.Select(x => new SetpointValueDto {
|
||||||
Key = x.Key,
|
Key = x.Key,
|
||||||
Value = DeserializeValue(x.Key, x.Value)
|
Value = x.Value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +37,7 @@ public class SetpointClient : BaseClient, ISetpointClient
|
|||||||
async () => await refitSetpointClient.GetCurrent(setpointConfigs, token), token);
|
async () => await refitSetpointClient.GetCurrent(setpointConfigs, token), token);
|
||||||
|
|
||||||
|
|
||||||
return result!.ToDictionary(x => x.Key,x => DeserializeValue(x.Key,x.Value));
|
return result!.ToDictionary(x => x.Key,x => (object)x.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
|
public async Task<IEnumerable<SetpointValueDto>> GetHistory(IEnumerable<Guid> setpointKeys, DateTimeOffset historyMoment, CancellationToken token)
|
||||||
@ -51,9 +45,6 @@ public class SetpointClient : BaseClient, ISetpointClient
|
|||||||
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!;
|
||||||
}
|
}
|
||||||
@ -63,9 +54,6 @@ 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!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +70,6 @@ public class SetpointClient : BaseClient, ISetpointClient
|
|||||||
var result = await ExecuteGetResponse(
|
var result = await ExecuteGetResponse(
|
||||||
async () => await refitSetpointClient.GetPart(dateBegin, take, token), token);
|
async () => await refitSetpointClient.GetPart(dateBegin, take, token), token);
|
||||||
|
|
||||||
DeserializeList(result);
|
|
||||||
|
|
||||||
return result!;
|
return result!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,21 +87,4 @@ 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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
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;
|
||||||
@ -19,8 +19,7 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
|||||||
this.refitTimestampedSetClient = refitTimestampedSetClientFactory.Create();
|
this.refitTimestampedSetClient = refitTimestampedSetClientFactory.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
private readonly ConcurrentDictionary<Guid, TimestampedSetMapperBase> mapperCache = new();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> sets, CancellationToken token)
|
public async Task<int> AddRange(Guid discriminatorId, IEnumerable<TimestampedValuesDto> sets, CancellationToken token)
|
||||||
@ -39,15 +38,6 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
|||||||
return result!;
|
return result!;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public async Task<IEnumerable<T>> Get<T>(Guid discriminatorId, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable<string>? columnNames, int skip, int take, CancellationToken token)
|
|
||||||
{
|
|
||||||
var data = await Get([discriminatorId], geTimestamp, filterTree, columnNames, skip, take, token);
|
|
||||||
var mapper = GetMapper<T>(discriminatorId);
|
|
||||||
|
|
||||||
return data.Select(mapper.DeserializeTimeStampedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<IEnumerable<TimestampedValuesDto>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token)
|
public async Task<IEnumerable<TimestampedValuesDto>> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token)
|
||||||
{
|
{
|
||||||
@ -102,20 +92,7 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
using DD.Persistence.Client.Clients;
|
using DD.Persistence.Client.Clients;
|
||||||
using DD.Persistence.Client.Clients.Interfaces;
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Mapping;
|
||||||
|
using DD.Persistence.Client.Clients.Mapping.Abstractions;
|
||||||
|
using DD.Persistence.Client.Clients.Mapping.Clients;
|
||||||
using DD.Persistence.Models;
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Configurations;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace DD.Persistence.Client;
|
namespace DD.Persistence.Client;
|
||||||
@ -15,7 +19,7 @@ public static class DependencyInjection
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="services"></param>
|
/// <param name="services"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IServiceCollection AddPersistenceClients(this IServiceCollection services, Dictionary<Guid, Type>? setpointTypeConfigs = null)
|
public static IServiceCollection AddPersistenceClients(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddTransient(typeof(IRefitClientFactory<>), typeof(RefitClientFactory<>));
|
services.AddTransient(typeof(IRefitClientFactory<>), typeof(RefitClientFactory<>));
|
||||||
services.AddTransient<IChangeLogClient, ChangeLogClient>();
|
services.AddTransient<IChangeLogClient, ChangeLogClient>();
|
||||||
@ -25,10 +29,17 @@ public static class DependencyInjection
|
|||||||
services.AddTransient<ITimestampedValuesClient, TimestampedValuesClient>();
|
services.AddTransient<ITimestampedValuesClient, TimestampedValuesClient>();
|
||||||
services.AddTransient<IWitsDataClient, WitsDataClient>();
|
services.AddTransient<IWitsDataClient, WitsDataClient>();
|
||||||
|
|
||||||
services.AddSingleton<ISetpointConfigStorage, SetpointConfigStorage>(provider =>
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
on.nemtina
commented
Dictionary<Guid, Type>? mappingConfigs - не nullable Dictionary<Guid, Type>? mappingConfigs - не nullable
|
|||||||
|
|
||||||
|
public static IServiceCollection AddPersistenceMapping(this IServiceCollection services, MappingConfig mappingConfigs)
|
||||||
{
|
{
|
||||||
return new SetpointConfigStorage(setpointTypeConfigs);
|
services.AddSingleton(mappingConfigs);
|
||||||
});
|
services.AddSingleton<IMapperStorage, MapperStorage>();
|
||||||
|
|
||||||
|
services.AddTransient<ISetpointMappingClient, SetpointMappingClient>();
|
||||||
|
services.AddTransient<ITimestampedMappingClient, TimestampedMappingClient>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
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,20 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,10 @@
|
|||||||
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.Client.Clients.Interfaces.Refit;
|
||||||
|
using DD.Persistence.Client.Clients.Mapping.Clients;
|
||||||
using DD.Persistence.Database.Entity;
|
using DD.Persistence.Database.Entity;
|
||||||
|
using DD.Persistence.Models.Configurations;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -13,17 +13,14 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
public class SetpointControllerTest : BaseIntegrationTest
|
public class SetpointControllerTest : BaseIntegrationTest
|
||||||
{
|
{
|
||||||
private readonly ISetpointClient setpointClient;
|
private readonly ISetpointClient setpointClient;
|
||||||
private readonly SetpointConfigStorage configStorage;
|
|
||||||
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
|
||||||
{
|
{
|
||||||
var refitClientFactory = scope.ServiceProvider
|
var refitClientFactory = scope.ServiceProvider
|
||||||
.GetRequiredService<IRefitClientFactory<IRefitSetpointClient>>();
|
.GetRequiredService<IRefitClientFactory<IRefitSetpointClient>>();
|
||||||
var logger = scope.ServiceProvider.GetRequiredService<ILogger<SetpointClient>>();
|
|
||||||
|
|
||||||
setpointClient = scope.ServiceProvider
|
setpointClient = scope.ServiceProvider
|
||||||
.GetRequiredService<ISetpointClient>();
|
.GetRequiredService<ISetpointClient>();
|
||||||
|
|
||||||
configStorage = (SetpointConfigStorage)scope.ServiceProvider.GetRequiredService<ISetpointConfigStorage>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -32,12 +29,16 @@ namespace DD.Persistence.IntegrationTests.Controllers
|
|||||||
{
|
{
|
||||||
var id = Guid.Parse("e0fcad22-1761-476e-a729-a3c59d51ba41");
|
var id = Guid.Parse("e0fcad22-1761-476e-a729-a3c59d51ba41");
|
||||||
|
|
||||||
configStorage.AddOrReplace(id, typeof(float));
|
var config = new MappingConfig();
|
||||||
|
config[id] = typeof(float);
|
||||||
|
|
||||||
|
var setpointMapper = new SetpointMappingClient(setpointClient, config);
|
||||||
|
|
||||||
|
|
||||||
await setpointClient.Add(id, 48.3f, CancellationToken.None);
|
await setpointClient.Add(id, 48.3f, CancellationToken.None);
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var response = await setpointClient.GetCurrent([id], CancellationToken.None);
|
var response = await setpointMapper.GetCurrent([id], CancellationToken.None);
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
|
4
DD.Persistence.Models/Configurations/MappingConfig.cs
Normal file
4
DD.Persistence.Models/Configurations/MappingConfig.cs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
namespace DD.Persistence.Models.Configurations;
|
||||||
|
public class MappingConfig : Dictionary<Guid, Type>
|
||||||
|
{
|
||||||
|
}
|
@ -7,6 +7,11 @@ namespace DD.Persistence.Models;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class TimestampedValuesDto : ITimestampAbstractDto
|
public class TimestampedValuesDto : ITimestampAbstractDto
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Дискриминатор
|
||||||
|
/// </summary>
|
||||||
|
public Guid DiscriminatorId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Временная отметка
|
/// Временная отметка
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\DD.Persistence.API\DD.Persistence.API.csproj" />
|
<ProjectReference Include="..\DD.Persistence.API\DD.Persistence.API.csproj" />
|
||||||
|
<ProjectReference Include="..\DD.Persistence.Client\DD.Persistence.Client.csproj" />
|
||||||
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
|
<ProjectReference Include="..\DD.Persistence.Database.Postgres\DD.Persistence.Database.Postgres.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
99
DD.Persistence.Test/MappingClientsTest.cs
Normal file
99
DD.Persistence.Test/MappingClientsTest.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using DD.Persistence.Client.Clients.Interfaces;
|
||||||
|
using DD.Persistence.Client.Clients.Mapping;
|
||||||
|
using DD.Persistence.Client.Clients.Mapping.Clients;
|
||||||
|
using DD.Persistence.Models;
|
||||||
|
using DD.Persistence.Models.Configurations;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using NSubstitute;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Test;
|
||||||
|
|
||||||
|
public record FirstTestDto(Guid DiscriminatorId, DateTimeOffset Timestamp, int Id, string? Value);
|
||||||
|
|
||||||
|
public record SecondTestDto(Guid DiscriminatorId, DateTimeOffset Timestamp, int Id, double Capacity);
|
||||||
|
|
||||||
|
public class MappingClientsTest
|
||||||
|
{
|
||||||
|
private readonly ITimestampedValuesClient timestampedValuesClient = Substitute.For<ITimestampedValuesClient>();
|
||||||
|
private readonly ILogger<TimestampedSetMapper> logger = Substitute.For<ILogger<TimestampedSetMapper>>();
|
||||||
|
private readonly TimestampedMappingClient timestampedMappingClient;
|
||||||
|
|
||||||
|
private readonly MappingConfig mappingConfigs;
|
||||||
|
|
||||||
|
|
||||||
|
public MappingClientsTest()
|
||||||
|
{
|
||||||
|
mappingConfigs = GetConfig();
|
||||||
|
var storage = new MapperStorage(mappingConfigs, logger);
|
||||||
|
|
||||||
|
timestampedMappingClient = new TimestampedMappingClient(timestampedValuesClient, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetMultiMapped()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var discriminatorIds = mappingConfigs.Keys;
|
||||||
|
var firstDiscriminatorId = discriminatorIds.First();
|
||||||
|
var secondDiscriminatorId = discriminatorIds.Last();
|
||||||
|
var getResult = new[]
|
||||||
|
{
|
||||||
|
new TimestampedValuesDto()
|
||||||
|
{
|
||||||
|
DiscriminatorId = firstDiscriminatorId,
|
||||||
|
Timestamp = DateTime.UtcNow,
|
||||||
|
Values = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ nameof(FirstTestDto.Id), JsonDocument.Parse(JsonSerializer.Serialize(1)).RootElement },
|
||||||
|
{ nameof(FirstTestDto.Value), JsonDocument.Parse(JsonSerializer.Serialize("string1")).RootElement}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new TimestampedValuesDto()
|
||||||
|
{
|
||||||
|
DiscriminatorId = secondDiscriminatorId,
|
||||||
|
Timestamp = DateTime.UtcNow,
|
||||||
|
Values = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ nameof(SecondTestDto.Id), JsonDocument.Parse(JsonSerializer.Serialize(1)).RootElement },
|
||||||
|
{ nameof(SecondTestDto.Capacity), JsonDocument.Parse(JsonSerializer.Serialize(0.1)).RootElement}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timestampedValuesClient
|
||||||
|
.Get(discriminatorIds, null, null, null, 0, 1, CancellationToken.None)
|
||||||
|
.ReturnsForAnyArgs(getResult);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await timestampedMappingClient.GetMultiMapped(discriminatorIds, null, null, null, 0, 1, CancellationToken.None);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result);
|
||||||
|
Assert.NotEmpty(result);
|
||||||
|
Assert.Equal(getResult.Count(), result.Count());
|
||||||
|
|
||||||
|
var firstActualDto = (FirstTestDto) result[firstDiscriminatorId].First();
|
||||||
|
Assert.NotNull(firstActualDto);
|
||||||
|
|
||||||
|
var actualId = firstActualDto.Id.ToString();
|
||||||
|
var expectedId = getResult[0].Values[nameof(FirstTestDto.Id)].ToString();
|
||||||
|
Assert.Equal(expectedId, actualId);
|
||||||
|
|
||||||
|
var secondActualDto = (SecondTestDto) result[secondDiscriminatorId].First();
|
||||||
|
Assert.NotNull(secondActualDto);
|
||||||
|
|
||||||
|
actualId = secondActualDto.Id.ToString();
|
||||||
|
expectedId = getResult[1].Values[nameof(SecondTestDto.Id)].ToString();
|
||||||
|
Assert.Equal(expectedId, actualId);
|
||||||
|
}
|
||||||
|
private MappingConfig GetConfig()
|
||||||
|
{
|
||||||
|
var config = new MappingConfig();
|
||||||
|
config[Guid.NewGuid()] = typeof(FirstTestDto);
|
||||||
|
config[Guid.NewGuid()] = typeof(SecondTestDto);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
@ -122,6 +122,7 @@ public class TimestampedValuesService : ITimestampedValuesService
|
|||||||
{
|
{
|
||||||
var dto = new TimestampedValuesDto()
|
var dto = new TimestampedValuesDto()
|
||||||
{
|
{
|
||||||
|
DiscriminatorId = keyValuePair.Key,
|
||||||
Timestamp = Timestamp.ToUniversalTime(),
|
Timestamp = Timestamp.ToUniversalTime(),
|
||||||
Values = dataScheme
|
Values = dataScheme
|
||||||
.ToDictionary(k => k.PropertyName, v => Values[v.Index])
|
.ToDictionary(k => k.PropertyName, v => Values[v.Index])
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||||
<_Parameter1>DD.Persistence.IntegrationTests</_Parameter1>
|
<_Parameter1>DD.Persistence.IntegrationTests</_Parameter1>
|
||||||
</AssemblyAttribute>
|
</AssemblyAttribute>
|
||||||
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||||
|
<_Parameter1>DD.Persistence.Test</_Parameter1>
|
||||||
|
</AssemblyAttribute>
|
||||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||||
<_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
|
<_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
|
||||||
</AssemblyAttribute>
|
</AssemblyAttribute>
|
||||||
|
Loading…
Reference in New Issue
Block a user
пусть будет result, также как сейчас в остальных методах