diff --git a/DD.Persistence.API/DD.Persistence.API.csproj b/DD.Persistence.API/DD.Persistence.API.csproj index 5ed1097..38dd298 100644 --- a/DD.Persistence.API/DD.Persistence.API.csproj +++ b/DD.Persistence.API/DD.Persistence.API.csproj @@ -25,7 +25,6 @@ - diff --git a/DD.Persistence.API/Startup.cs b/DD.Persistence.API/Startup.cs index 1a880c0..f19e6cf 100644 --- a/DD.Persistence.API/Startup.cs +++ b/DD.Persistence.API/Startup.cs @@ -1,6 +1,6 @@ -using DD.Persistence.Database.Model; +using DD.Persistence.Database; +using DD.Persistence.Database.Model; using DD.Persistence.Database.Postgres.Extensions; -using DD.Persistence.Repository; namespace DD.Persistence.API; @@ -14,7 +14,7 @@ public class Startup public void ConfigureServices(IServiceCollection services) { - // Add services to the container. + // AddRange services to the container. services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle diff --git a/DD.Persistence.Database.Postgres/DependencyInjection.cs b/DD.Persistence.Database.Postgres/DependencyInjection.cs index f0c8ff1..df84bb3 100644 --- a/DD.Persistence.Database.Postgres/DependencyInjection.cs +++ b/DD.Persistence.Database.Postgres/DependencyInjection.cs @@ -1,6 +1,13 @@ -using Microsoft.EntityFrameworkCore; +using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Postgres.Repositories; +using DD.Persistence.Database.Postgres.RepositoriesCached; +using DD.Persistence.Models; +using DD.Persistence.Repositories; +using Mapster; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using System.Reflection; namespace DD.Persistence.Database.Model; diff --git a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs b/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.Designer.cs similarity index 90% rename from DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs rename to DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.Designer.cs index bdeaf87..b90d452 100644 --- a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs +++ b/DD.Persistence.Database.Postgres/Migrations/20250205114037_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("20250205114037_Init")] partial class Init { /// @@ -67,23 +67,6 @@ namespace DD.Persistence.Database.Postgres.Migrations b.ToTable("change_log"); }); - modelBuilder.Entity("DD.Persistence.Database.Entity.DataScheme", b => - { - b.Property("DiscriminatorId") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasComment("Идентификатор схемы данных"); - - b.Property("PropNames") - .IsRequired() - .HasColumnType("jsonb") - .HasComment("Наименования полей в порядке индексации"); - - b.HasKey("DiscriminatorId"); - - b.ToTable("data_scheme"); - }); - modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b => { b.Property("SystemId") @@ -129,6 +112,30 @@ namespace DD.Persistence.Database.Postgres.Migrations b.ToTable("parameter_data"); }); + modelBuilder.Entity("DD.Persistence.Database.Entity.SchemeProperty", b => + { + b.Property("DiscriminatorId") + .HasColumnType("uuid") + .HasComment("Идентификатор схемы данных"); + + b.Property("Index") + .HasColumnType("integer") + .HasComment("Индекс поля"); + + b.Property("PropertyKind") + .HasColumnType("smallint") + .HasComment("Тип индексируемого поля"); + + b.Property("PropertyName") + .IsRequired() + .HasColumnType("text") + .HasComment("Наименования индексируемого поля"); + + b.HasKey("DiscriminatorId", "Index"); + + b.ToTable("scheme_property"); + }); + modelBuilder.Entity("DD.Persistence.Database.Entity.Setpoint", b => { b.Property("Key") @@ -217,17 +224,6 @@ namespace DD.Persistence.Database.Postgres.Migrations 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 } } diff --git a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs b/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs similarity index 91% rename from DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs rename to DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs index df996bc..c872547 100644 --- a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs +++ b/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs @@ -30,18 +30,6 @@ namespace DD.Persistence.Database.Postgres.Migrations table.PrimaryKey("PK_change_log", x => x.Id); }); - migrationBuilder.CreateTable( - name: "data_scheme", - columns: table => new - { - DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"), - PropNames = table.Column(type: "jsonb", nullable: false, comment: "Наименования полей в порядке индексации") - }, - constraints: table => - { - table.PrimaryKey("PK_data_scheme", x => x.DiscriminatorId); - }); - migrationBuilder.CreateTable( name: "data_source_system", columns: table => new @@ -69,6 +57,20 @@ namespace DD.Persistence.Database.Postgres.Migrations table.PrimaryKey("PK_parameter_data", x => new { x.DiscriminatorId, x.ParameterId, x.Timestamp }); }); + migrationBuilder.CreateTable( + name: "scheme_property", + columns: table => new + { + DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"), + Index = table.Column(type: "integer", nullable: false, comment: "Индекс поля"), + PropertyName = table.Column(type: "text", nullable: false, comment: "Наименования индексируемого поля"), + PropertyKind = table.Column(type: "smallint", nullable: false, comment: "Тип индексируемого поля") + }, + constraints: table => + { + table.PrimaryKey("PK_scheme_property", x => new { x.DiscriminatorId, x.Index }); + }); + migrationBuilder.CreateTable( name: "setpoint", columns: table => new @@ -94,12 +96,6 @@ namespace DD.Persistence.Database.Postgres.Migrations constraints: table => { table.PrimaryKey("PK_timestamped_values", x => new { x.DiscriminatorId, x.Timestamp }); - table.ForeignKey( - name: "FK_timestamped_values_data_scheme_DiscriminatorId", - column: x => x.DiscriminatorId, - principalTable: "data_scheme", - principalColumn: "DiscriminatorId", - onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( @@ -139,6 +135,9 @@ namespace DD.Persistence.Database.Postgres.Migrations migrationBuilder.DropTable( name: "parameter_data"); + migrationBuilder.DropTable( + name: "scheme_property"); + migrationBuilder.DropTable( name: "setpoint"); @@ -150,9 +149,6 @@ namespace DD.Persistence.Database.Postgres.Migrations migrationBuilder.DropTable( name: "data_source_system"); - - migrationBuilder.DropTable( - name: "data_scheme"); } } } diff --git a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs index 5c5ad2e..e2b0921 100644 --- a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs +++ b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs @@ -64,23 +64,6 @@ namespace DD.Persistence.Database.Postgres.Migrations b.ToTable("change_log"); }); - modelBuilder.Entity("DD.Persistence.Database.Entity.DataScheme", b => - { - b.Property("DiscriminatorId") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasComment("Идентификатор схемы данных"); - - b.Property("PropNames") - .IsRequired() - .HasColumnType("jsonb") - .HasComment("Наименования полей в порядке индексации"); - - b.HasKey("DiscriminatorId"); - - b.ToTable("data_scheme"); - }); - modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b => { b.Property("SystemId") @@ -126,6 +109,30 @@ namespace DD.Persistence.Database.Postgres.Migrations b.ToTable("parameter_data"); }); + modelBuilder.Entity("DD.Persistence.Database.Entity.SchemeProperty", b => + { + b.Property("DiscriminatorId") + .HasColumnType("uuid") + .HasComment("Идентификатор схемы данных"); + + b.Property("Index") + .HasColumnType("integer") + .HasComment("Индекс поля"); + + b.Property("PropertyKind") + .HasColumnType("smallint") + .HasComment("Тип индексируемого поля"); + + b.Property("PropertyName") + .IsRequired() + .HasColumnType("text") + .HasComment("Наименования индексируемого поля"); + + b.HasKey("DiscriminatorId", "Index"); + + b.ToTable("scheme_property"); + }); + modelBuilder.Entity("DD.Persistence.Database.Entity.Setpoint", b => { b.Property("Key") @@ -214,17 +221,6 @@ namespace DD.Persistence.Database.Postgres.Migrations 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 } } diff --git a/DD.Persistence.Database/DD.Persistence.Database.csproj b/DD.Persistence.Database/DD.Persistence.Database.csproj index 9303e6a..65f8d54 100644 --- a/DD.Persistence.Database/DD.Persistence.Database.csproj +++ b/DD.Persistence.Database/DD.Persistence.Database.csproj @@ -7,11 +7,13 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/DD.Persistence.Repository/DependencyInjection.cs b/DD.Persistence.Database/DependencyInjection.cs similarity index 60% rename from DD.Persistence.Repository/DependencyInjection.cs rename to DD.Persistence.Database/DependencyInjection.cs index a6ae2af..a9291e2 100644 --- a/DD.Persistence.Repository/DependencyInjection.cs +++ b/DD.Persistence.Database/DependencyInjection.cs @@ -1,15 +1,19 @@ -using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Postgres.Repositories; +using DD.Persistence.Database.Postgres.RepositoriesCached; +using DD.Persistence.Database.Repositories; +using DD.Persistence.Database.RepositoriesCached; using DD.Persistence.Models; using DD.Persistence.Repositories; -using DD.Persistence.Repository.Repositories; -using DD.Persistence.Repository.RepositoriesCached; using Mapster; using Microsoft.Extensions.DependencyInjection; using System.Reflection; -namespace DD.Persistence.Repository; +namespace DD.Persistence.Database; + public static class DependencyInjection { + // ToDo: перенести в другой файл public static void MapsterSetup() { TypeAdapterConfig.GlobalSettings.Default.Config @@ -22,6 +26,12 @@ public static class DependencyInjection Value = src.Value, Id = src.Id }); + + TypeAdapterConfig, SchemeProperty>.NewConfig() + .Map(dest => dest.DiscriminatorId, src => src.Key) + .Map(dest => dest.Index, src => src.Value.Index) + .Map(dest => dest.PropertyKind, src => src.Value.PropertyKind) + .Map(dest => dest.PropertyName, src => src.Value.PropertyName); } public static IServiceCollection AddInfrastructure(this IServiceCollection services) @@ -37,8 +47,8 @@ public static class DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); return services; } diff --git a/DD.Persistence.Database/Entity/DataScheme.cs b/DD.Persistence.Database/Entity/DataScheme.cs deleted file mode 100644 index 75794c0..0000000 --- a/DD.Persistence.Database/Entity/DataScheme.cs +++ /dev/null @@ -1,15 +0,0 @@ -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; } = []; -} diff --git a/DD.Persistence.Database/Entity/SchemeProperty.cs b/DD.Persistence.Database/Entity/SchemeProperty.cs new file mode 100644 index 0000000..6ef5bdb --- /dev/null +++ b/DD.Persistence.Database/Entity/SchemeProperty.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json; + +namespace DD.Persistence.Database.Entity; + +[Table("scheme_property")] +[PrimaryKey(nameof(DiscriminatorId), nameof(Index))] +public class SchemeProperty +{ + [Comment("Идентификатор схемы данных")] + public Guid DiscriminatorId { get; set; } + + [Comment("Индекс поля")] + public int Index { get; set; } + + [Comment("Наименования индексируемого поля")] + public required string PropertyName { get; set; } + + [Comment("Тип индексируемого поля")] + public required JsonValueKind PropertyKind { get; set; } +} diff --git a/DD.Persistence.Database/Entity/TimestampedValues.cs b/DD.Persistence.Database/Entity/TimestampedValues.cs index a2835f7..d28e1cf 100644 --- a/DD.Persistence.Database/Entity/TimestampedValues.cs +++ b/DD.Persistence.Database/Entity/TimestampedValues.cs @@ -17,7 +17,4 @@ public class TimestampedValues : ITimestampedItem [Comment("Данные"), Column(TypeName = "jsonb")] public required object[] Values { get; set; } - - [Required, ForeignKey(nameof(DiscriminatorId)), Comment("Идентификаторы")] - public virtual DataScheme? DataScheme { get; set; } } diff --git a/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs b/DD.Persistence.Database/Extensions/EFExtensionsSortBy.cs similarity index 99% rename from DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs rename to DD.Persistence.Database/Extensions/EFExtensionsSortBy.cs index bed529e..10818a4 100644 --- a/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs +++ b/DD.Persistence.Database/Extensions/EFExtensionsSortBy.cs @@ -2,7 +2,7 @@ using System.Collections.Concurrent; using System.Linq.Expressions; using System.Reflection; -namespace DD.Persistence.Repository.Extensions; +namespace DD.Persistence.Database.Extensions; public static class EFExtensionsSortBy { diff --git a/DD.Persistence.Repository/CyclicArray.cs b/DD.Persistence.Database/Helpers/CyclicArray.cs similarity index 99% rename from DD.Persistence.Repository/CyclicArray.cs rename to DD.Persistence.Database/Helpers/CyclicArray.cs index 7a7ea1d..fcb5793 100644 --- a/DD.Persistence.Repository/CyclicArray.cs +++ b/DD.Persistence.Database/Helpers/CyclicArray.cs @@ -1,6 +1,6 @@ using System.Collections; -namespace DD.Persistence.Repository; +namespace DD.Persistence.Database.Postgres.Helpers; /// /// Цикличный массив /// diff --git a/DD.Persistence.Repository/QueryBuilders.cs b/DD.Persistence.Database/Helpers/QueryBuilders.cs similarity index 90% rename from DD.Persistence.Repository/QueryBuilders.cs rename to DD.Persistence.Database/Helpers/QueryBuilders.cs index 52b6429..8529230 100644 --- a/DD.Persistence.Repository/QueryBuilders.cs +++ b/DD.Persistence.Database/Helpers/QueryBuilders.cs @@ -1,11 +1,10 @@ -using Microsoft.EntityFrameworkCore; -using DD.Persistence.Models.Requests; -using DD.Persistence.Models.Common; -using DD.Persistence.ModelsAbstractions; -using DD.Persistence.Database.EntityAbstractions; +using DD.Persistence.Database.EntityAbstractions; using DD.Persistence.Extensions; +using DD.Persistence.Models.Common; +using DD.Persistence.Models.Requests; +using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository; +namespace DD.Persistence.Database.Postgres.Helpers; /// /// класс с набором методов, необходимых для фильтрации записей @@ -55,4 +54,4 @@ public static class QueryBuilders return result; } -} +} \ No newline at end of file diff --git a/DD.Persistence.Database/PersistenceDbContext.cs b/DD.Persistence.Database/PersistenceDbContext.cs index fbbc057..4b0a874 100644 --- a/DD.Persistence.Database/PersistenceDbContext.cs +++ b/DD.Persistence.Database/PersistenceDbContext.cs @@ -10,7 +10,7 @@ public class PersistenceDbContext : DbContext { public DbSet Setpoint => Set(); - public DbSet DataSchemes => Set(); + public DbSet SchemeProperty => Set(); public DbSet TimestampedValues => Set(); @@ -30,10 +30,6 @@ public class PersistenceDbContext : DbContext protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.Entity() - .Property(e => e.PropNames) - .HasJsonConversion(); - modelBuilder.Entity() .Property(e => e.Values) .HasJsonConversion(); diff --git a/DD.Persistence.Repository/Repositories/ChangeLogRepository.cs b/DD.Persistence.Database/Repositories/ChangeLogRepository.cs similarity index 96% rename from DD.Persistence.Repository/Repositories/ChangeLogRepository.cs rename to DD.Persistence.Database/Repositories/ChangeLogRepository.cs index 2af06ce..61e907d 100644 --- a/DD.Persistence.Repository/Repositories/ChangeLogRepository.cs +++ b/DD.Persistence.Database/Repositories/ChangeLogRepository.cs @@ -1,4 +1,5 @@ using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Postgres.Helpers; using DD.Persistence.Models; using DD.Persistence.Models.Common; using DD.Persistence.Models.Requests; @@ -7,7 +8,7 @@ using Mapster; using Microsoft.EntityFrameworkCore; using UuidExtensions; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Repositories; public class ChangeLogRepository : IChangeLogRepository { private readonly DbContext db; @@ -185,7 +186,7 @@ public class ChangeLogRepository : IChangeLogRepository var datesUpdate = await datesUpdateQuery.ToArrayAsync(token); - var dates = Enumerable.Concat(datesCreate, datesUpdate); + var dates = datesCreate.Concat(datesUpdate); var datesOnly = dates .Select(d => new DateOnly(d.Year, d.Month, d.Day)) .Distinct() @@ -213,7 +214,7 @@ public class ChangeLogRepository : IChangeLogRepository public async Task> GetGtDate(Guid idDiscriminator, DateTimeOffset dateBegin, CancellationToken token) { var date = dateBegin.ToUniversalTime(); - var query = this.db.Set() + var query = db.Set() .Where(e => e.IdDiscriminator == idDiscriminator) .Where(e => e.Creation >= date || e.Obsolete >= date); @@ -232,7 +233,7 @@ public class ChangeLogRepository : IChangeLogRepository .Select(group => new { Min = group.Min(e => e.Creation), - Max = group.Max(e => (e.Obsolete.HasValue && e.Obsolete > e.Creation) + Max = group.Max(e => e.Obsolete.HasValue && e.Obsolete > e.Creation ? e.Obsolete.Value : e.Creation), }); diff --git a/DD.Persistence.Repository/Repositories/DataSourceSystemRepository.cs b/DD.Persistence.Database/Repositories/DataSourceSystemRepository.cs similarity index 94% rename from DD.Persistence.Repository/Repositories/DataSourceSystemRepository.cs rename to DD.Persistence.Database/Repositories/DataSourceSystemRepository.cs index d8b6c0a..d9e7fa7 100644 --- a/DD.Persistence.Repository/Repositories/DataSourceSystemRepository.cs +++ b/DD.Persistence.Database/Repositories/DataSourceSystemRepository.cs @@ -4,7 +4,7 @@ using DD.Persistence.Repositories; using Mapster; using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Postgres.Repositories; public class DataSourceSystemRepository : IDataSourceSystemRepository { protected DbContext db; diff --git a/DD.Persistence.Repository/Repositories/ParameterRepository.cs b/DD.Persistence.Database/Repositories/ParameterRepository.cs similarity index 98% rename from DD.Persistence.Repository/Repositories/ParameterRepository.cs rename to DD.Persistence.Database/Repositories/ParameterRepository.cs index d241de7..c489cd7 100644 --- a/DD.Persistence.Repository/Repositories/ParameterRepository.cs +++ b/DD.Persistence.Database/Repositories/ParameterRepository.cs @@ -5,7 +5,7 @@ using DD.Persistence.Models; using DD.Persistence.Repositories; using DD.Persistence.Models.Common; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Postgres.Repositories; public class ParameterRepository : IParameterRepository { private DbContext db; diff --git a/DD.Persistence.Database/Repositories/SchemePropertyRepository.cs b/DD.Persistence.Database/Repositories/SchemePropertyRepository.cs new file mode 100644 index 0000000..26bb8aa --- /dev/null +++ b/DD.Persistence.Database/Repositories/SchemePropertyRepository.cs @@ -0,0 +1,43 @@ +using DD.Persistence.Database.Entity; +using DD.Persistence.Models; +using DD.Persistence.Repositories; +using Mapster; +using Microsoft.EntityFrameworkCore; + +namespace DD.Persistence.Database.Repositories; +public class SchemePropertyRepository : ISchemePropertyRepository +{ + protected DbContext db; + public SchemePropertyRepository(DbContext db) + { + this.db = db; + } + protected virtual IQueryable GetQueryReadOnly() => db.Set(); + + public virtual async Task AddRange(DataSchemeDto dataSchemeDto, CancellationToken token) + { + var entities = dataSchemeDto.Select(e => + KeyValuePair.Create(dataSchemeDto.DiscriminatorId, e) + .Adapt() + ); + + await db.Set().AddRangeAsync(entities, token); + await db.SaveChangesAsync(token); + } + + public virtual async Task Get(Guid dataSchemeId, CancellationToken token) + { + var query = GetQueryReadOnly() + .Where(e => e.DiscriminatorId == dataSchemeId); + var entities = await query.ToArrayAsync(token); + + DataSchemeDto? result = null; + if (entities.Length != 0) + { + var properties = entities.Select(e => e.Adapt()).ToArray(); + result = new DataSchemeDto(dataSchemeId, properties); + } + + return result; + } +} diff --git a/DD.Persistence.Repository/Repositories/SetpointRepository.cs b/DD.Persistence.Database/Repositories/SetpointRepository.cs similarity index 98% rename from DD.Persistence.Repository/Repositories/SetpointRepository.cs rename to DD.Persistence.Database/Repositories/SetpointRepository.cs index 97c6098..3cfd9b1 100644 --- a/DD.Persistence.Repository/Repositories/SetpointRepository.cs +++ b/DD.Persistence.Database/Repositories/SetpointRepository.cs @@ -6,7 +6,7 @@ using Mapster; using Microsoft.EntityFrameworkCore; using System.Text.Json; -namespace DD.Persistence.Repository.Repositories +namespace DD.Persistence.Database.Postgres.Repositories { public class SetpointRepository : ISetpointRepository { diff --git a/DD.Persistence.Repository/Repositories/TechMessagesRepository.cs b/DD.Persistence.Database/Repositories/TechMessagesRepository.cs similarity index 98% rename from DD.Persistence.Repository/Repositories/TechMessagesRepository.cs rename to DD.Persistence.Database/Repositories/TechMessagesRepository.cs index 1a84f25..15d8fe8 100644 --- a/DD.Persistence.Repository/Repositories/TechMessagesRepository.cs +++ b/DD.Persistence.Database/Repositories/TechMessagesRepository.cs @@ -7,7 +7,7 @@ using DD.Persistence.Repositories; using Mapster; using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository.Repositories +namespace DD.Persistence.Database.Postgres.Repositories { public class TechMessagesRepository : ITechMessagesRepository { diff --git a/DD.Persistence.Repository/Repositories/TimestampedValuesRepository.cs b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs similarity index 99% rename from DD.Persistence.Repository/Repositories/TimestampedValuesRepository.cs rename to DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs index 2005a5a..5f3f60e 100644 --- a/DD.Persistence.Repository/Repositories/TimestampedValuesRepository.cs +++ b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs @@ -4,7 +4,7 @@ using DD.Persistence.Models.Common; using DD.Persistence.Repositories; using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Postgres.Repositories; public class TimestampedValuesRepository : ITimestampedValuesRepository { private readonly DbContext db; diff --git a/DD.Persistence.Repository/RepositoriesCached/DataSourceSystemCachedRepository.cs b/DD.Persistence.Database/RepositoriesCached/DataSourceSystemCachedRepository.cs similarity index 91% rename from DD.Persistence.Repository/RepositoriesCached/DataSourceSystemCachedRepository.cs rename to DD.Persistence.Database/RepositoriesCached/DataSourceSystemCachedRepository.cs index 87e487e..919c3ba 100644 --- a/DD.Persistence.Repository/RepositoriesCached/DataSourceSystemCachedRepository.cs +++ b/DD.Persistence.Database/RepositoriesCached/DataSourceSystemCachedRepository.cs @@ -1,10 +1,10 @@ using DD.Persistence.Database.Entity; using DD.Persistence.Models; -using DD.Persistence.Repository.Repositories; +using DD.Persistence.Database.Postgres.Repositories; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; -namespace DD.Persistence.Repository.RepositoriesCached; +namespace DD.Persistence.Database.Postgres.RepositoriesCached; public class DataSourceSystemCachedRepository : DataSourceSystemRepository { private static readonly string SystemCacheKey = $"{typeof(DataSourceSystem).FullName}CacheKey"; diff --git a/DD.Persistence.Repository/RepositoriesCached/DataSchemeCachedRepository.cs b/DD.Persistence.Database/RepositoriesCached/SchemePropertyCachedRepository.cs similarity index 57% rename from DD.Persistence.Repository/RepositoriesCached/DataSchemeCachedRepository.cs rename to DD.Persistence.Database/RepositoriesCached/SchemePropertyCachedRepository.cs index ea22196..64d9c01 100644 --- a/DD.Persistence.Repository/RepositoriesCached/DataSchemeCachedRepository.cs +++ b/DD.Persistence.Database/RepositoriesCached/SchemePropertyCachedRepository.cs @@ -1,21 +1,21 @@ using DD.Persistence.Models; -using DD.Persistence.Repository.Repositories; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; +using DD.Persistence.Database.Repositories; -namespace DD.Persistence.Repository.RepositoriesCached; -public class DataSchemeCachedRepository : DataSchemeRepository +namespace DD.Persistence.Database.RepositoriesCached; +public class SchemePropertyCachedRepository : SchemePropertyRepository { private readonly IMemoryCache memoryCache; - public DataSchemeCachedRepository(DbContext db, IMemoryCache memoryCache) : base(db) + public SchemePropertyCachedRepository(DbContext db, IMemoryCache memoryCache) : base(db) { this.memoryCache = memoryCache; } - public override async Task Add(DataSchemeDto dataSourceSystemDto, CancellationToken token) + public override async Task AddRange(DataSchemeDto dataSourceSystemDto, CancellationToken token) { - await base.Add(dataSourceSystemDto, token); + await base.AddRange(dataSourceSystemDto, token); memoryCache.Set(dataSourceSystemDto.DiscriminatorId, dataSourceSystemDto); } diff --git a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs index c6642a5..9bb1d58 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); @@ -407,8 +406,12 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest private void Cleanup() { + foreach (var item in discriminatorIds) + { + memoryCache.Remove(item); + } discriminatorIds = []; dbContext.CleanupDbSet(); - dbContext.CleanupDbSet(); + dbContext.CleanupDbSet(); } } diff --git a/DD.Persistence.Models/DataSchemeDto.cs b/DD.Persistence.Models/DataSchemeDto.cs index d1efdd5..2b28176 100644 --- a/DD.Persistence.Models/DataSchemeDto.cs +++ b/DD.Persistence.Models/DataSchemeDto.cs @@ -1,9 +1,11 @@ -namespace DD.Persistence.Models; +using System.Collections; + +namespace DD.Persistence.Models; /// /// Схема для набора данных /// -public class DataSchemeDto +public class DataSchemeDto : IEnumerable, IEquatable> { /// /// Дискриминатор @@ -11,7 +13,30 @@ public class DataSchemeDto public Guid DiscriminatorId { get; set; } /// - /// Наименования полей + /// Поля /// - public string[] PropNames { get; set; } = []; + private IEnumerable Properties { get; } = []; + + /// + public DataSchemeDto(Guid discriminatorId, IEnumerable Properties) + { + DiscriminatorId = discriminatorId; + this.Properties = Properties; + } + + /// + public IEnumerator GetEnumerator() + => Properties.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + public bool Equals(IEnumerable? otherProperties) + { + if (otherProperties is null) + return false; + + return Properties.SequenceEqual(otherProperties); + } } diff --git a/DD.Persistence.Models/SchemePropertyDto.cs b/DD.Persistence.Models/SchemePropertyDto.cs new file mode 100644 index 0000000..0c34ba7 --- /dev/null +++ b/DD.Persistence.Models/SchemePropertyDto.cs @@ -0,0 +1,30 @@ +using System.Text.Json; + +namespace DD.Persistence.Models; + +/// +/// Индексируемого поле из схемы для набора данных +/// +public class SchemePropertyDto : IEquatable +{ + /// + /// Индекс поля + /// + public required int Index { get; set; } + + /// + /// Наименование индексируемого поля + /// + public required string PropertyName { get; set; } + + /// + /// Тип индексируемого поля + /// + public required JsonValueKind PropertyKind { get; set; } + + /// + public bool Equals(SchemePropertyDto? other) + { + return Index == other?.Index && PropertyName == other?.PropertyName && PropertyKind == other?.PropertyKind; + } +} diff --git a/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj b/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj index 4f29d86..63b4134 100644 --- a/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj +++ b/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj @@ -20,7 +20,6 @@ - diff --git a/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs b/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs index 6b05ff3..44c518a 100644 --- a/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs +++ b/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs @@ -1,12 +1,7 @@ using DD.Persistence.Database.Model; -using DD.Persistence.Repository.Repositories; +using DD.Persistence.Database.Postgres.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 diff --git a/DD.Persistence.Repository/DD.Persistence.Repository.csproj b/DD.Persistence.Repository/DD.Persistence.Repository.csproj deleted file mode 100644 index 75803db..0000000 --- a/DD.Persistence.Repository/DD.Persistence.Repository.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net9.0 - enable - enable - - - - - - - - - - - - - diff --git a/DD.Persistence.Repository/Repositories/DataSchemeRepository.cs b/DD.Persistence.Repository/Repositories/DataSchemeRepository.cs deleted file mode 100644 index c30c8da..0000000 --- a/DD.Persistence.Repository/Repositories/DataSchemeRepository.cs +++ /dev/null @@ -1,34 +0,0 @@ -using DD.Persistence.Database.Entity; -using DD.Persistence.Models; -using DD.Persistence.Repositories; -using Mapster; -using Microsoft.EntityFrameworkCore; - -namespace DD.Persistence.Repository.Repositories; -public class DataSchemeRepository : IDataSchemeRepository -{ - protected DbContext db; - public DataSchemeRepository(DbContext db) - { - this.db = db; - } - protected virtual IQueryable GetQueryReadOnly() => db.Set(); - - public virtual async Task Add(DataSchemeDto dataSourceSystemDto, CancellationToken token) - { - var entity = dataSourceSystemDto.Adapt(); - - await db.Set().AddAsync(entity, token); - await db.SaveChangesAsync(token); - } - - public virtual async Task Get(Guid dataSchemeId, CancellationToken token) - { - var query = GetQueryReadOnly() - .Where(e => e.DiscriminatorId == dataSchemeId); - var entity = await query.ToArrayAsync(); - var dto = entity.Select(e => e.Adapt()).FirstOrDefault(); - - return dto; - } -} diff --git a/DD.Persistence.Repository/RepositoriesCached/TimestampedValuesCachedRepository.cs b/DD.Persistence.Repository/RepositoriesCached/TimestampedValuesCachedRepository.cs deleted file mode 100644 index f81f7a0..0000000 --- a/DD.Persistence.Repository/RepositoriesCached/TimestampedValuesCachedRepository.cs +++ /dev/null @@ -1,103 +0,0 @@ -//using DD.Persistence.Models; -//using DD.Persistence.Models.Common; -//using DD.Persistence.Repositories; -//using Microsoft.EntityFrameworkCore; - -//namespace DD.Persistence.Repository.Repositories; - -//public class TimestampedValuesCachedRepository : TimestampedValuesRepository -//{ -// public static TimestampedValuesDto? FirstByDate { get; private set; } -// public static CyclicArray LastData { get; } = new CyclicArray(CacheItemsCount); - -// private const int CacheItemsCount = 3600; - -// public TimestampedValuesCachedRepository(DbContext db, IDataSourceSystemRepository relatedDataRepository) : base(db, relatedDataRepository) -// { -// //Task.Run(async () => -// //{ -// // var firstDateItem = await base.GetFirst(CancellationToken.None); -// // if (firstDateItem == null) -// // { -// // return; -// // } - -// // FirstByDate = firstDateItem; - -// // var dtos = await base.GetLast(CacheItemsCount, CancellationToken.None); -// // dtos = dtos.OrderBy(d => d.Timestamp); -// // LastData.AddRange(dtos); -// //}).Wait(); -// } - -// public override async Task> GetGtDate(Guid discriminatorId, DateTimeOffset dateBegin, CancellationToken token) -// { - -// if (LastData.Count == 0 || LastData[0].Timestamp > dateBegin) -// { -// var dtos = await base.GetGtDate(discriminatorId, dateBegin, token); -// return dtos; -// } - -// var items = LastData -// .Where(i => i.Timestamp >= dateBegin); - -// return items; -// } - -// public override async Task AddRange(Guid discriminatorId, IEnumerable dtos, CancellationToken token) -// { -// var result = await base.AddRange(discriminatorId, dtos, token); -// if (result > 0) -// { - -// dtos = dtos.OrderBy(x => x.Timestamp); - -// FirstByDate = dtos.First(); -// LastData.AddRange(dtos); -// } - -// return result; -// } - -// public override async Task GetDatesRange(Guid discriminatorId, CancellationToken token) -// { -// if (FirstByDate == null) -// return null; - -// return await Task.Run(() => -// { -// return new DatesRangeDto -// { -// From = FirstByDate.Timestamp, -// To = LastData[^1].Timestamp -// }; -// }); -// } - -// public override async Task> GetResampledData( -// Guid discriminatorId, -// DateTimeOffset dateBegin, -// double intervalSec = 600d, -// int approxPointsCount = 1024, -// CancellationToken token = default) -// { -// var dtos = LastData.Where(i => i.Timestamp >= dateBegin); -// if (LastData.Count == 0 || LastData[0].Timestamp > dateBegin) -// { -// dtos = await base.GetGtDate(discriminatorId, dateBegin, token); -// } - -// var dateEnd = dateBegin.AddSeconds(intervalSec); -// dtos = dtos -// .Where(i => i.Timestamp <= dateEnd); - -// var ratio = dtos.Count() / approxPointsCount; -// if (ratio > 1) -// dtos = dtos -// .Where((_, index) => index % ratio == 0); - -// return dtos; -// } -//} - diff --git a/DD.Persistence.Test/TimestampedValuesServiceShould.cs b/DD.Persistence.Test/TimestampedValuesServiceShould.cs index 0acb6de..0fe7769 100644 --- a/DD.Persistence.Test/TimestampedValuesServiceShould.cs +++ b/DD.Persistence.Test/TimestampedValuesServiceShould.cs @@ -2,12 +2,13 @@ using DD.Persistence.Repositories; using DD.Persistence.Services; using NSubstitute; +using System.Text.Json; namespace DD.Persistence.Repository.Test; public class TimestampedValuesServiceShould { private readonly ITimestampedValuesRepository timestampedValuesRepository = Substitute.For(); - private readonly IDataSchemeRepository dataSchemeRepository = Substitute.For(); + private readonly ISchemePropertyRepository dataSchemeRepository = Substitute.For(); private TimestampedValuesService timestampedValuesService; public TimestampedValuesServiceShould() @@ -45,10 +46,10 @@ public class TimestampedValuesServiceShould { var values = new Dictionary() { - { "A", i }, - { "B", i * 1.1 }, - { "C", $"Any{i}" }, - { "D", DateTimeOffset.Now }, + { "A", GetJsonFromObject(i) }, + { "B", GetJsonFromObject(i * 1.1) }, + { "C", GetJsonFromObject($"Any{i}") }, + { "D", GetJsonFromObject(DateTimeOffset.Now) } }; yield return new TimestampedValuesDto() @@ -58,4 +59,11 @@ public class TimestampedValuesServiceShould }; } } + + private static JsonElement GetJsonFromObject(object value) + { + var jsonString = JsonSerializer.Serialize(value); + var doc = JsonDocument.Parse(jsonString); + return doc.RootElement; + } } diff --git a/DD.Persistence.sln b/DD.Persistence.sln index ca91e47..e42f411 100644 --- a/DD.Persistence.sln +++ b/DD.Persistence.sln @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence", "DD.Persis EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.API", "DD.Persistence.API\DD.Persistence.API.csproj", "{8650A227-929E-45F0-AEF7-2C91F45FE884}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.Repository", "DD.Persistence.Repository\DD.Persistence.Repository.csproj", "{493D6D92-231B-4CB6-831B-BE13884B0DE4}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.Database", "DD.Persistence.Database\DD.Persistence.Database.csproj", "{F77475D1-D074-407A-9D69-2FADDDAE2056}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.IntegrationTests", "DD.Persistence.IntegrationTests\DD.Persistence.IntegrationTests.csproj", "{10752C25-3773-4081-A1F2-215A1D950126}" @@ -51,10 +49,6 @@ Global {8650A227-929E-45F0-AEF7-2C91F45FE884}.Debug|Any CPU.Build.0 = Debug|Any CPU {8650A227-929E-45F0-AEF7-2C91F45FE884}.Release|Any CPU.ActiveCfg = Release|Any CPU {8650A227-929E-45F0-AEF7-2C91F45FE884}.Release|Any CPU.Build.0 = Release|Any CPU - {493D6D92-231B-4CB6-831B-BE13884B0DE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {493D6D92-231B-4CB6-831B-BE13884B0DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {493D6D92-231B-4CB6-831B-BE13884B0DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {493D6D92-231B-4CB6-831B-BE13884B0DE4}.Release|Any CPU.Build.0 = Release|Any CPU {F77475D1-D074-407A-9D69-2FADDDAE2056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F77475D1-D074-407A-9D69-2FADDDAE2056}.Debug|Any CPU.Build.0 = Debug|Any CPU {F77475D1-D074-407A-9D69-2FADDDAE2056}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/DD.Persistence/Repositories/IDataSchemeRepository.cs b/DD.Persistence/Repositories/ISchemePropertyRepository.cs similarity index 84% rename from DD.Persistence/Repositories/IDataSchemeRepository.cs rename to DD.Persistence/Repositories/ISchemePropertyRepository.cs index c14a9cf..458f5cd 100644 --- a/DD.Persistence/Repositories/IDataSchemeRepository.cs +++ b/DD.Persistence/Repositories/ISchemePropertyRepository.cs @@ -5,7 +5,7 @@ namespace DD.Persistence.Repositories; /// /// Репозиторий для работы со схемами наборов данных /// -public interface IDataSchemeRepository +public interface ISchemePropertyRepository { /// /// Добавить схему @@ -13,7 +13,7 @@ public interface IDataSchemeRepository /// /// /// - Task Add(DataSchemeDto dataSourceSystemDto, CancellationToken token); + Task AddRange(DataSchemeDto dataSourceSystemDto, CancellationToken token); /// /// Вычитать схему diff --git a/DD.Persistence/Services/TimestampedValuesService.cs b/DD.Persistence/Services/TimestampedValuesService.cs index cbcb73c..cef700f 100644 --- a/DD.Persistence/Services/TimestampedValuesService.cs +++ b/DD.Persistence/Services/TimestampedValuesService.cs @@ -1,8 +1,8 @@ using DD.Persistence.Extensions; using DD.Persistence.Models; -using DD.Persistence.Models.Common; using DD.Persistence.Repositories; using DD.Persistence.Services.Interfaces; +using System.Text.Json; namespace DD.Persistence.Services; @@ -10,10 +10,10 @@ namespace DD.Persistence.Services; public class TimestampedValuesService : ITimestampedValuesService { private readonly ITimestampedValuesRepository timestampedValuesRepository; - private readonly IDataSchemeRepository dataSchemeRepository; + private readonly ISchemePropertyRepository dataSchemeRepository; /// - public TimestampedValuesService(ITimestampedValuesRepository timestampedValuesRepository, IDataSchemeRepository relatedDataRepository) + public TimestampedValuesService(ITimestampedValuesRepository timestampedValuesRepository, ISchemePropertyRepository relatedDataRepository) { this.timestampedValuesRepository = timestampedValuesRepository; this.dataSchemeRepository = relatedDataRepository; @@ -25,8 +25,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); @@ -39,7 +38,7 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.Get(discriminatorIds, geTimestamp, columnNames, skip, take, token); - var dtos = await Materialize(result, token); + var dtos = await BindingToDataScheme(result, token); if (!columnNames.IsNullOrEmpty()) { @@ -54,9 +53,9 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.GetFirst(discriminatorId, takeCount, token); - var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) } + var resultBeforeBinding = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); - var dtos = await Materialize(resultToMaterialize, token); + var dtos = await BindingToDataScheme(resultBeforeBinding, token); return dtos; } @@ -66,9 +65,9 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.GetLast(discriminatorId, takeCount, token); - var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) } + var resultBeforeBinding = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); - var dtos = await Materialize(resultToMaterialize, token); + var dtos = await BindingToDataScheme(resultBeforeBinding, token); return dtos; } @@ -83,9 +82,9 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.GetResampledData(discriminatorId, beginTimestamp, intervalSec, approxPointsCount, token); - var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) } + var resultBeforeBinding = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); - var dtos = await Materialize(resultToMaterialize, token); + var dtos = await BindingToDataScheme(resultBeforeBinding, token); return dtos; } @@ -94,42 +93,37 @@ 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) } + + var resultBeforeBinding = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); - var dtos = await Materialize(resultToMaterialize, token); + var dtos = await BindingToDataScheme(resultBeforeBinding, token); return dtos; } + // ToDo: рефакторинг, переименовать (текущее название не отражает суть) /// /// Преобразовать результат запроса в набор dto /// /// /// /// - private async Task> Materialize(IDictionary> queryResult, CancellationToken token) + private async Task> BindingToDataScheme(IDictionary> queryResult, CancellationToken token) { IEnumerable result = []; foreach (var keyValuePair in queryResult) { var dataScheme = await dataSchemeRepository.Get(keyValuePair.Key, token); if (dataScheme is null) - { continue; - } - foreach (var tuple in keyValuePair.Value) + foreach (var (Timestamp, Values) 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]) + Timestamp = Timestamp.ToUniversalTime(), + Values = dataScheme + .ToDictionary(k => k.PropertyName, v => Values[v.Index]) }; result = result.Append(dto); @@ -140,34 +134,36 @@ 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 valuesList = dto.Values.ToList(); + var properties = valuesList.Select((e, index) => new SchemePropertyDto() { - systemSpecification = new DataSchemeDto() - { - DiscriminatorId = discriminatorId, - PropNames = fieldNames - }; - await dataSchemeRepository.Add(systemSpecification, token); + Index = index, + PropertyName = e.Key, + PropertyKind = ((JsonElement)e.Value).ValueKind + }); + + var dataScheme = await dataSchemeRepository.Get(discriminatorId, token); + if (dataScheme is null) + { + dataScheme = new DataSchemeDto(discriminatorId, properties); + await dataSchemeRepository.AddRange(dataScheme, token); return; } - if (!systemSpecification.PropNames.SequenceEqual(fieldNames)) + if (!dataScheme.Equals(properties)) { - var expectedFieldNames = string.Join(", ", systemSpecification.PropNames); - var actualFieldNames = string.Join(", ", fieldNames); throw new InvalidOperationException($"Для системы {discriminatorId.ToString()} " + - $"характерен набор данных: [{expectedFieldNames}], однако был передан набор: [{actualFieldNames}]"); + $"был передан нехарактерный набор данных"); } } @@ -177,7 +173,7 @@ public class TimestampedValuesService : ITimestampedValuesService /// /// Поля, которые необходимо оставить /// - private IEnumerable ReduceSetColumnsByNames(IEnumerable dtos, IEnumerable fieldNames) + private static IEnumerable ReduceSetColumnsByNames(IEnumerable dtos, IEnumerable fieldNames) { var result = dtos.Select(dto => {