diff --git a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs b/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs
similarity index 97%
rename from DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs
rename to DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs
index bdeaf87..60e6e92 100644
--- a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs
+++ b/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs
@@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace DD.Persistence.Database.Postgres.Migrations
{
[DbContext(typeof(PersistencePostgresContext))]
- [Migration("20250203061429_Init")]
+ [Migration("20250204044050_Init")]
partial class Init
{
///
@@ -79,6 +79,11 @@ namespace DD.Persistence.Database.Postgres.Migrations
.HasColumnType("jsonb")
.HasComment("Наименования полей в порядке индексации");
+ b.PrimitiveCollection("PropTypes")
+ .IsRequired()
+ .HasColumnType("integer[]")
+ .HasComment("Типы полей в порядке индексации");
+
b.HasKey("DiscriminatorId");
b.ToTable("data_scheme");
diff --git a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs b/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs
similarity index 97%
rename from DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs
rename to DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs
index df996bc..24a310d 100644
--- a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs
+++ b/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs
@@ -35,7 +35,8 @@ namespace DD.Persistence.Database.Postgres.Migrations
columns: table => new
{
DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"),
- PropNames = table.Column(type: "jsonb", nullable: false, comment: "Наименования полей в порядке индексации")
+ PropNames = table.Column(type: "jsonb", nullable: false, comment: "Наименования полей в порядке индексации"),
+ PropTypes = table.Column(type: "integer[]", nullable: false, comment: "Типы полей в порядке индексации")
},
constraints: table =>
{
diff --git a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs
index 5c5ad2e..ca319a5 100644
--- a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs
+++ b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs
@@ -76,6 +76,11 @@ namespace DD.Persistence.Database.Postgres.Migrations
.HasColumnType("jsonb")
.HasComment("Наименования полей в порядке индексации");
+ b.PrimitiveCollection("PropTypes")
+ .IsRequired()
+ .HasColumnType("integer[]")
+ .HasComment("Типы полей в порядке индексации");
+
b.HasKey("DiscriminatorId");
b.ToTable("data_scheme");
diff --git a/DD.Persistence.Database/Entity/DataScheme.cs b/DD.Persistence.Database/Entity/DataScheme.cs
index 75794c0..a231580 100644
--- a/DD.Persistence.Database/Entity/DataScheme.cs
+++ b/DD.Persistence.Database/Entity/DataScheme.cs
@@ -1,4 +1,5 @@
-using Microsoft.EntityFrameworkCore;
+using DD.Persistence.Models;
+using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@@ -12,4 +13,7 @@ public class DataScheme
[Comment("Наименования полей в порядке индексации"), Column(TypeName = "jsonb")]
public string[] PropNames { get; set; } = [];
+
+ [Comment("Типы полей в порядке индексации")]
+ public PropTypeEnum[] PropTypes { get; set; } = [];
}
diff --git a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs
index c6642a5..526b372 100644
--- a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs
+++ b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs
@@ -3,7 +3,6 @@ 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.Extensions;
using DD.Persistence.Models;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
@@ -267,7 +266,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest
var count = 2048;
var timestampBegin = DateTimeOffset.UtcNow;
var dtos = await AddRange(discriminatorId, count);
-
+
//act
var response = await timestampedValuesClient.GetResampledData(discriminatorId, timestampBegin, count);
diff --git a/DD.Persistence.Models/DataSchemeDto.cs b/DD.Persistence.Models/DataSchemeDto.cs
index d1efdd5..7f238aa 100644
--- a/DD.Persistence.Models/DataSchemeDto.cs
+++ b/DD.Persistence.Models/DataSchemeDto.cs
@@ -14,4 +14,9 @@ public class DataSchemeDto
/// Наименования полей
///
public string[] PropNames { get; set; } = [];
+
+ ///
+ /// Типы полей
+ ///
+ public PropTypeEnum[] PropTypes { get; set; } = [];
}
diff --git a/DD.Persistence.Models/Enumerations/PropTypeEnum.cs b/DD.Persistence.Models/Enumerations/PropTypeEnum.cs
new file mode 100644
index 0000000..5379929
--- /dev/null
+++ b/DD.Persistence.Models/Enumerations/PropTypeEnum.cs
@@ -0,0 +1,14 @@
+namespace DD.Persistence.Models;
+
+///
+/// Типы для набора данных
+///
+public enum PropTypeEnum
+{
+ ///
+ String = 0,
+ ///
+ Double = 1,
+ ///
+ DateTime = 2
+}
diff --git a/DD.Persistence/Services/TimestampedValuesService.cs b/DD.Persistence/Services/TimestampedValuesService.cs
index cbcb73c..fc17777 100644
--- a/DD.Persistence/Services/TimestampedValuesService.cs
+++ b/DD.Persistence/Services/TimestampedValuesService.cs
@@ -1,6 +1,5 @@
using DD.Persistence.Extensions;
using DD.Persistence.Models;
-using DD.Persistence.Models.Common;
using DD.Persistence.Repositories;
using DD.Persistence.Services.Interfaces;
@@ -25,8 +24,7 @@ public class TimestampedValuesService : ITimestampedValuesService
// ToDo: реализовать без foreach
foreach (var dto in dtos)
{
- var keys = dto.Values.Keys.ToArray();
- await CreateSystemSpecificationIfNotExist(discriminatorId, keys, token);
+ await CreateDataSchemeIfNotExist(discriminatorId, dto, token);
}
var result = await timestampedValuesRepository.AddRange(discriminatorId, dtos, token);
@@ -94,7 +92,7 @@ public class TimestampedValuesService : ITimestampedValuesService
public async Task> GetGtDate(Guid discriminatorId, DateTimeOffset beginTimestamp, CancellationToken token)
{
var result = await timestampedValuesRepository.GetGtDate(discriminatorId, beginTimestamp, token);
-
+
var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) }
.ToDictionary();
var dtos = await Materialize(resultToMaterialize, token);
@@ -140,37 +138,69 @@ public class TimestampedValuesService : ITimestampedValuesService
}
///
- /// Создать спецификацию, при отсутствии таковой
+ /// Создать схему данных, при отсутствии таковой
///
- /// Дискриминатор системы
- /// Набор наименований полей
+ /// Дискриминатор схемы
+ /// Набор данных, по образу которого будет создана соответствующая схема
///
///
/// Некорректный набор наименований полей
- private async Task CreateSystemSpecificationIfNotExist(Guid discriminatorId, string[] fieldNames, CancellationToken token)
+ private async Task CreateDataSchemeIfNotExist(Guid discriminatorId, TimestampedValuesDto dto, CancellationToken token)
{
- var systemSpecification = await dataSchemeRepository.Get(discriminatorId, token);
- if (systemSpecification is null)
+ var propNames = dto.Values.Keys.ToArray();
+ var propTypes = GetPropTypes(dto);
+
+ var dataScheme = await dataSchemeRepository.Get(discriminatorId, token);
+ if (dataScheme is null)
{
- systemSpecification = new DataSchemeDto()
+ dataScheme = new DataSchemeDto()
{
DiscriminatorId = discriminatorId,
- PropNames = fieldNames
+ PropNames = propNames,
+ PropTypes = propTypes
};
- await dataSchemeRepository.Add(systemSpecification, token);
+ await dataSchemeRepository.Add(dataScheme, token);
return;
}
- if (!systemSpecification.PropNames.SequenceEqual(fieldNames))
+ if (!dataScheme.PropNames.SequenceEqual(propNames))
{
- var expectedFieldNames = string.Join(", ", systemSpecification.PropNames);
- var actualFieldNames = string.Join(", ", fieldNames);
+ var expectedFieldNames = string.Join(", ", dataScheme.PropNames);
+ var actualFieldNames = string.Join(", ", propNames);
throw new InvalidOperationException($"Для системы {discriminatorId.ToString()} " +
$"характерен набор данных: [{expectedFieldNames}], однако был передан набор: [{actualFieldNames}]");
}
}
+ ///
+ /// Получить типы для набора данных в соответствии с индексацией
+ ///
+ ///
+ ///
+ ///
+ private PropTypeEnum[] GetPropTypes(TimestampedValuesDto dto)
+ {
+ var types = dto.Values.Select(e =>
+ {
+ var valueString = e.Value.ToString();
+
+ if (valueString is null)
+ throw new ArgumentNullException("Переданный набор данных содержит null, в следствии чего не удаётся определить типы полей");
+
+ if (DateTimeOffset.TryParse(valueString, out _))
+ return PropTypeEnum.DateTime;
+
+ var doubleString = valueString.Replace('.', ',');
+ if (double.TryParse(doubleString, out _))
+ return PropTypeEnum.Double;
+
+ return PropTypeEnum.String;
+ });
+
+ return types.ToArray();
+ }
+
///
/// Отсеить лишние поля в соответствии с заданным фильтром
///