From 8e2c3a3a55b7d28f97dc97a7b2e90d104030555d Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Mon, 10 Feb 2025 09:27:13 +0500 Subject: [PATCH 01/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=B0=D1=80=D1=81=D0=B8=D0=BD=D0=B3=20?= =?UTF-8?q?=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20=D0=B2=20Get-=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimestampedValuesController.cs | 11 +++++-- DD.Persistence.API/DependencyInjection.cs | 11 ++++--- .../{ => Operation}/AndSpecification.cs | 2 +- .../{ => Operation}/OrSpecification.cs | 4 +-- .../Filter/Models/Abstractions/TNode.cs | 29 ++++++++++++++++++- .../Terminal/Abstract/TerminalExpression.cs | 11 ++----- 6 files changed, 48 insertions(+), 20 deletions(-) rename DD.Persistence.Database/Specifications/{ => Operation}/AndSpecification.cs (90%) rename DD.Persistence.Database/Specifications/{ => Operation}/OrSpecification.cs (79%) diff --git a/DD.Persistence.API/Controllers/TimestampedValuesController.cs b/DD.Persistence.API/Controllers/TimestampedValuesController.cs index fe97476..56b0db6 100644 --- a/DD.Persistence.API/Controllers/TimestampedValuesController.cs +++ b/DD.Persistence.API/Controllers/TimestampedValuesController.cs @@ -1,4 +1,5 @@ -using DD.Persistence.Models; +using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Models; using DD.Persistence.Models.Common; using DD.Persistence.Repositories; using DD.Persistence.Services.Interfaces; @@ -45,6 +46,7 @@ public class TimestampedValuesController : ControllerBase /// /// Набор дискриминаторов /// Фильтр позднее даты + /// Кастомный фильтр по набору значений /// Фильтр свойств набора /// /// @@ -52,7 +54,12 @@ public class TimestampedValuesController : ControllerBase [HttpGet] [ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.NoContent)] - public async Task>> Get([FromQuery] IEnumerable discriminatorIds, DateTimeOffset? timestampBegin, [FromQuery] string[]? columnNames, int skip, int take, CancellationToken token) + public async Task>> Get([FromQuery] IEnumerable discriminatorIds, + DateTimeOffset? timestampBegin, + [FromQuery] TNode? filterTree, + [FromQuery] string[]? columnNames, + int skip, int take, + CancellationToken token) { var result = await timestampedValuesService.Get(discriminatorIds, timestampBegin, columnNames, skip, take, token); diff --git a/DD.Persistence.API/DependencyInjection.cs b/DD.Persistence.API/DependencyInjection.cs index b543841..30d9f89 100644 --- a/DD.Persistence.API/DependencyInjection.cs +++ b/DD.Persistence.API/DependencyInjection.cs @@ -1,16 +1,14 @@ -using Mapster; +using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Models.Configurations; +using DD.Persistence.Services; +using DD.Persistence.Services.Interfaces; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; -using DD.Persistence.Models; -using DD.Persistence.Models.Configurations; -using DD.Persistence.Services; -using DD.Persistence.Services.Interfaces; using Swashbuckle.AspNetCore.SwaggerGen; using System.Reflection; using System.Text.Json.Nodes; -using DD.Persistence.Database.Entity; namespace DD.Persistence.API; @@ -30,6 +28,7 @@ public static class DependencyInjection new OpenApiSchema {Type = "number", Format = "float" } ] }); + c.MapType(() => new OpenApiSchema { Type = "string" }); c.CustomOperationIds(e => { diff --git a/DD.Persistence.Database/Specifications/AndSpecification.cs b/DD.Persistence.Database/Specifications/Operation/AndSpecification.cs similarity index 90% rename from DD.Persistence.Database/Specifications/AndSpecification.cs rename to DD.Persistence.Database/Specifications/Operation/AndSpecification.cs index 776ce3a..a085183 100644 --- a/DD.Persistence.Database/Specifications/AndSpecification.cs +++ b/DD.Persistence.Database/Specifications/Operation/AndSpecification.cs @@ -1,6 +1,6 @@ using Ardalis.Specification; -namespace DD.Persistence.Database.Specifications; +namespace DD.Persistence.Database.Specifications.Operation; public class AndSpecification : Specification { public AndSpecification(ISpecification first, ISpecification second) diff --git a/DD.Persistence.Database/Specifications/OrSpecification.cs b/DD.Persistence.Database/Specifications/Operation/OrSpecification.cs similarity index 79% rename from DD.Persistence.Database/Specifications/OrSpecification.cs rename to DD.Persistence.Database/Specifications/Operation/OrSpecification.cs index 75e573e..db07f6e 100644 --- a/DD.Persistence.Database/Specifications/OrSpecification.cs +++ b/DD.Persistence.Database/Specifications/Operation/OrSpecification.cs @@ -1,13 +1,13 @@ using Ardalis.Specification; using DD.Persistence.Database.Postgres.Extensions; -namespace DD.Persistence.Database.Specifications; +namespace DD.Persistence.Database.Specifications.Operation; public class OrSpecification : Specification { public OrSpecification(ISpecification first, ISpecification second) { var orExpression = first.Or(second); - if (orExpression == null) + if (orExpression == null) return; Query.Where(orExpression); diff --git a/DD.Persistence/Filter/Models/Abstractions/TNode.cs b/DD.Persistence/Filter/Models/Abstractions/TNode.cs index 226a3ef..2046a55 100644 --- a/DD.Persistence/Filter/Models/Abstractions/TNode.cs +++ b/DD.Persistence/Filter/Models/Abstractions/TNode.cs @@ -1,11 +1,14 @@ using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder; +using System.Diagnostics.CodeAnalysis; namespace DD.Persistence.Filter.Models.Abstractions; /// /// Абстрактная модель вершины /// -public abstract class TNode + +public abstract class TNode : IParsable { /// public TNode(OperationEnum operation) @@ -18,6 +21,30 @@ public abstract class TNode /// public OperationEnum Operation { get; } + /// + public static TNode? Parse(string s, IFormatProvider? provider) + { + var result = s.BuildTree(); + + return result; + } + + /// + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out TNode result) + { + if (string.IsNullOrEmpty(s)) + { + result = default(TNode); + return false; + } + + result = s.BuildTree(); + if (result is null) + return false; + + return true; + } + /// /// Принять посетителя /// diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs index 1d13d6b..00ee20f 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs @@ -62,15 +62,10 @@ abstract class TerminalExpression : IExpression private static object? ParseValue(string value) { - value = value.Replace('.', ','); - if (value.Contains(',') && double.TryParse(value, out _)) + var doubleValue= value.Replace('.', ','); + if (double.TryParse(doubleValue, out _)) { - return double.Parse(value); - } - - if (int.TryParse(value, out _)) - { - return int.Parse(value); + return double.Parse(doubleValue); } value = value.Trim('\"'); From 2fe369d49e0c797ce98eb412f82807699b4a9942 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Mon, 10 Feb 2025 17:25:45 +0500 Subject: [PATCH 02/12] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B2=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20TimestampedValuesRepository=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=20=D1=81=D0=BF=D0=B5=D1=86=D0=B8=D1=84=D0=B8=D0=BA=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimestampedValuesController.cs | 2 +- .../Interfaces/ITimestampedValuesClient.cs | 5 +- .../Refit/IRefitTimestampedValuesClient.cs | 1 + .../Clients/TimestampedValuesClient.cs | 8 +-- ...ner.cs => 20250210055116_Init.Designer.cs} | 10 +-- ...5114037_Init.cs => 20250210055116_Init.cs} | 2 +- ...PersistencePostgresContextModelSnapshot.cs | 8 +-- .../DependencyInjection.cs | 2 + DD.Persistence.Database/Entity/ChangeLog.cs | 4 +- .../Entity/ParameterData.cs | 2 +- .../Entity/SchemeProperty.cs | 5 +- DD.Persistence.Database/Entity/TechMessage.cs | 18 ++--- .../Entity/TimestampedValues.cs | 2 +- .../EntityAbstractions/IChangeLog.cs | 2 +- .../EntityAbstractions/IDiscriminatorItem.cs | 8 +++ .../Extensions/SpecificationExtensions.cs | 60 ++++++++++++++++ .../Helpers/FilterBuilder.cs | 33 +++++---- .../Repositories/ChangeLogRepository.cs | 16 ++--- .../TimestampedValuesRepository.cs | 70 +++++++++++++------ .../DiscriminatorContainsSpec.cs | 12 ++++ .../DiscriminatorEqualSpec.cs | 12 ++++ .../DiscriminatorGroupSpec.cs | 18 +++++ .../TimestampedItem/FirstSequenceSpec.cs | 14 ++++ .../Common/TimestampedItem/GeTimestampSpec.cs | 17 +++++ .../ValuesItem/ValueEqaulSpec.cs} | 8 +-- .../ValuesItem/ValueGreateOrEqualSpec.cs} | 8 +-- .../ValuesItem/ValueGreateSpec.cs} | 8 +-- .../ValuesItem/ValueLessOrEqualSpec.cs} | 8 +-- .../ValuesItem/ValueLessSpec.cs} | 8 +-- .../ValuesItem/ValueNotEqualSpec.cs} | 8 +-- .../{AndSpecification.cs => AndSpec.cs} | 4 +- .../{OrSpecification.cs => OrSpec.cs} | 4 +- .../Controllers/ChangeLogControllerTest.cs | 4 +- .../TimestampedValuesControllerTest.cs | 8 ++- .../ITimestampedValuesRepository.cs | 5 +- .../Interfaces/ITimestampedValuesService.cs | 6 +- .../Services/TimestampedValuesService.cs | 5 +- 37 files changed, 299 insertions(+), 116 deletions(-) rename DD.Persistence.Database.Postgres/Migrations/{20250205114037_Init.Designer.cs => 20250210055116_Init.Designer.cs} (98%) rename DD.Persistence.Database.Postgres/Migrations/{20250205114037_Init.cs => 20250210055116_Init.cs} (99%) create mode 100644 DD.Persistence.Database/EntityAbstractions/IDiscriminatorItem.cs create mode 100644 DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorContainsSpec.cs create mode 100644 DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorEqualSpec.cs create mode 100644 DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorGroupSpec.cs create mode 100644 DD.Persistence.Database/Specifications/Common/TimestampedItem/FirstSequenceSpec.cs create mode 100644 DD.Persistence.Database/Specifications/Common/TimestampedItem/GeTimestampSpec.cs rename DD.Persistence.Database/Specifications/{ValuesItem/ValueEqaulSpecification.cs => Common/ValuesItem/ValueEqaulSpec.cs} (66%) rename DD.Persistence.Database/Specifications/{ValuesItem/ValueGreateOrEqualSpecification.cs => Common/ValuesItem/ValueGreateOrEqualSpec.cs} (65%) rename DD.Persistence.Database/Specifications/{ValuesItem/ValueGreateSpecification.cs => Common/ValuesItem/ValueGreateSpec.cs} (66%) rename DD.Persistence.Database/Specifications/{ValuesItem/ValueLessOrEqualSpecification.cs => Common/ValuesItem/ValueLessOrEqualSpec.cs} (66%) rename DD.Persistence.Database/Specifications/{ValuesItem/ValueLessSpecification.cs => Common/ValuesItem/ValueLessSpec.cs} (66%) rename DD.Persistence.Database/Specifications/{ValuesItem/ValueNotEqualSpecification.cs => Common/ValuesItem/ValueNotEqualSpec.cs} (65%) rename DD.Persistence.Database/Specifications/Operation/{AndSpecification.cs => AndSpec.cs} (74%) rename DD.Persistence.Database/Specifications/Operation/{OrSpecification.cs => OrSpec.cs} (65%) diff --git a/DD.Persistence.API/Controllers/TimestampedValuesController.cs b/DD.Persistence.API/Controllers/TimestampedValuesController.cs index 56b0db6..3d4bdf0 100644 --- a/DD.Persistence.API/Controllers/TimestampedValuesController.cs +++ b/DD.Persistence.API/Controllers/TimestampedValuesController.cs @@ -61,7 +61,7 @@ public class TimestampedValuesController : ControllerBase int skip, int take, CancellationToken token) { - var result = await timestampedValuesService.Get(discriminatorIds, timestampBegin, columnNames, skip, take, token); + var result = await timestampedValuesService.Get(discriminatorIds, timestampBegin, filterTree, columnNames, skip, take, token); return result.Any() ? Ok(result) : NoContent(); } diff --git a/DD.Persistence.Client/Clients/Interfaces/ITimestampedValuesClient.cs b/DD.Persistence.Client/Clients/Interfaces/ITimestampedValuesClient.cs index 27449b2..02a3987 100644 --- a/DD.Persistence.Client/Clients/Interfaces/ITimestampedValuesClient.cs +++ b/DD.Persistence.Client/Clients/Interfaces/ITimestampedValuesClient.cs @@ -24,12 +24,14 @@ public interface ITimestampedValuesClient : IDisposable /// /// Набор дискриминаторов (идентификаторов) /// Фильтр позднее даты + /// /// Фильтр свойств набора /// /// /// Task> Get(IEnumerable discriminatorIds, DateTimeOffset? timestampBegin, + string? filterTree, IEnumerable? columnNames, int skip, int take, @@ -40,11 +42,12 @@ public interface ITimestampedValuesClient : IDisposable /// /// /// + /// /// Фильтр свойств набора /// /// /// - Task> Get(Guid discriminatorId, DateTimeOffset? geTimestamp, IEnumerable? columnNames, int skip, int take, CancellationToken token); + Task> Get(Guid discriminatorId, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable? columnNames, int skip, int take, CancellationToken token); /// /// Получить данные, начиная с заданной отметки времени diff --git a/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitTimestampedValuesClient.cs b/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitTimestampedValuesClient.cs index 7c56f12..0858b08 100644 --- a/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitTimestampedValuesClient.cs +++ b/DD.Persistence.Client/Clients/Interfaces/Refit/IRefitTimestampedValuesClient.cs @@ -23,6 +23,7 @@ public interface IRefitTimestampedValuesClient : IRefitClient, IDisposable [Get($"{baseUrl}")] Task>> Get([Query(CollectionFormat.Multi)] IEnumerable discriminatorIds, DateTimeOffset? timestampBegin, + [Query] string? filterTree, [Query(CollectionFormat.Multi)] IEnumerable? columnNames, int skip, int take, diff --git a/DD.Persistence.Client/Clients/TimestampedValuesClient.cs b/DD.Persistence.Client/Clients/TimestampedValuesClient.cs index 123ed71..e4ad2a0 100644 --- a/DD.Persistence.Client/Clients/TimestampedValuesClient.cs +++ b/DD.Persistence.Client/Clients/TimestampedValuesClient.cs @@ -32,17 +32,17 @@ public class TimestampedValuesClient : BaseClient, ITimestampedValuesClient } /// - public async Task> Get(IEnumerable discriminatorIds, DateTimeOffset? geTimestamp, IEnumerable? columnNames, int skip, int take, CancellationToken token) + public async Task> Get(IEnumerable discriminatorIds, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable? columnNames, int skip, int take, CancellationToken token) { var result = await ExecuteGetResponse( - async () => await refitTimestampedSetClient.Get(discriminatorIds, geTimestamp, columnNames, skip, take, token), token); + async () => await refitTimestampedSetClient.Get(discriminatorIds, geTimestamp, filterTree, columnNames, skip, take, token), token); return result!; } /// - public async Task> Get(Guid discriminatorId, DateTimeOffset? geTimestamp, IEnumerable? columnNames, int skip, int take, CancellationToken token) + public async Task> Get(Guid discriminatorId, DateTimeOffset? geTimestamp, string? filterTree, IEnumerable? columnNames, int skip, int take, CancellationToken token) { - var data = await Get([discriminatorId], geTimestamp, columnNames, skip, take, token); + var data = await Get([discriminatorId], geTimestamp, filterTree, columnNames, skip, take, token); var mapper = GetMapper(discriminatorId); return data.Select(mapper.DeserializeTimeStampedData); diff --git a/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.Designer.cs b/DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.Designer.cs similarity index 98% rename from DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.Designer.cs rename to DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.Designer.cs index b90d452..5cd7da2 100644 --- a/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.Designer.cs +++ b/DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.Designer.cs @@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace DD.Persistence.Database.Postgres.Migrations { [DbContext(typeof(PersistencePostgresContext))] - [Migration("20250205114037_Init")] + [Migration("20250210055116_Init")] partial class Init { /// @@ -37,14 +37,14 @@ namespace DD.Persistence.Database.Postgres.Migrations .HasColumnType("timestamp with time zone") .HasComment("Дата создания записи"); + b.Property("DiscriminatorId") + .HasColumnType("uuid") + .HasComment("Дискриминатор таблицы"); + b.Property("IdAuthor") .HasColumnType("uuid") .HasComment("Автор изменения"); - b.Property("IdDiscriminator") - .HasColumnType("uuid") - .HasComment("Дискриминатор таблицы"); - b.Property("IdEditor") .HasColumnType("uuid") .HasComment("Редактор"); diff --git a/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs b/DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.cs similarity index 99% rename from DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs rename to DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.cs index c872547..a1dd229 100644 --- a/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs +++ b/DD.Persistence.Database.Postgres/Migrations/20250210055116_Init.cs @@ -17,7 +17,7 @@ namespace DD.Persistence.Database.Postgres.Migrations columns: table => new { Id = table.Column(type: "uuid", nullable: false, comment: "Ключ записи"), - IdDiscriminator = table.Column(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"), + DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Дискриминатор таблицы"), IdAuthor = table.Column(type: "uuid", nullable: false, comment: "Автор изменения"), IdEditor = table.Column(type: "uuid", nullable: true, comment: "Редактор"), Creation = table.Column(type: "timestamp with time zone", nullable: false, comment: "Дата создания записи"), diff --git a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs index e2b0921..59361b8 100644 --- a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs +++ b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs @@ -34,14 +34,14 @@ namespace DD.Persistence.Database.Postgres.Migrations .HasColumnType("timestamp with time zone") .HasComment("Дата создания записи"); + b.Property("DiscriminatorId") + .HasColumnType("uuid") + .HasComment("Дискриминатор таблицы"); + b.Property("IdAuthor") .HasColumnType("uuid") .HasComment("Автор изменения"); - b.Property("IdDiscriminator") - .HasColumnType("uuid") - .HasComment("Дискриминатор таблицы"); - b.Property("IdEditor") .HasColumnType("uuid") .HasComment("Редактор"); diff --git a/DD.Persistence.Database/DependencyInjection.cs b/DD.Persistence.Database/DependencyInjection.cs index a9291e2..91b6956 100644 --- a/DD.Persistence.Database/DependencyInjection.cs +++ b/DD.Persistence.Database/DependencyInjection.cs @@ -42,6 +42,8 @@ public static class DependencyInjection MapsterSetup(); + //services.AddTransient(typeof(PersistenceRepository)); + services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/DD.Persistence.Database/Entity/ChangeLog.cs b/DD.Persistence.Database/Entity/ChangeLog.cs index db1537a..a0047cb 100644 --- a/DD.Persistence.Database/Entity/ChangeLog.cs +++ b/DD.Persistence.Database/Entity/ChangeLog.cs @@ -11,13 +11,13 @@ namespace DD.Persistence.Database.Entity; /// Часть записи, описывающая изменение /// [Table("change_log")] -public class ChangeLog : IChangeLog +public class ChangeLog : IDiscriminatorItem, IChangeLog { [Key, Comment("Ключ записи")] public Guid Id { get; set; } [Comment("Дискриминатор таблицы")] - public Guid IdDiscriminator { get; set; } + public Guid DiscriminatorId { get; set; } [Comment("Автор изменения")] public Guid IdAuthor { get; set; } diff --git a/DD.Persistence.Database/Entity/ParameterData.cs b/DD.Persistence.Database/Entity/ParameterData.cs index 1b2fb37..638a5ba 100644 --- a/DD.Persistence.Database/Entity/ParameterData.cs +++ b/DD.Persistence.Database/Entity/ParameterData.cs @@ -7,7 +7,7 @@ namespace DD.Persistence.Database.Entity; [Table("parameter_data")] [PrimaryKey(nameof(DiscriminatorId), nameof(ParameterId), nameof(Timestamp))] -public class ParameterData : ITimestampedItem +public class ParameterData : IDiscriminatorItem, ITimestampedItem { [Required, Comment("Дискриминатор системы")] public Guid DiscriminatorId { get; set; } diff --git a/DD.Persistence.Database/Entity/SchemeProperty.cs b/DD.Persistence.Database/Entity/SchemeProperty.cs index 6ef5bdb..c7f64d5 100644 --- a/DD.Persistence.Database/Entity/SchemeProperty.cs +++ b/DD.Persistence.Database/Entity/SchemeProperty.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; +using DD.Persistence.Database.EntityAbstractions; +using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json; @@ -7,7 +8,7 @@ namespace DD.Persistence.Database.Entity; [Table("scheme_property")] [PrimaryKey(nameof(DiscriminatorId), nameof(Index))] -public class SchemeProperty +public class SchemeProperty : IDiscriminatorItem { [Comment("Идентификатор схемы данных")] public Guid DiscriminatorId { get; set; } diff --git a/DD.Persistence.Database/Entity/TechMessage.cs b/DD.Persistence.Database/Entity/TechMessage.cs index 093784f..8e8e84c 100644 --- a/DD.Persistence.Database/Entity/TechMessage.cs +++ b/DD.Persistence.Database/Entity/TechMessage.cs @@ -17,15 +17,15 @@ public class TechMessage : ITimestampedItem [Comment("Дата возникновения")] public DateTimeOffset Timestamp { get; set; } - [Column(TypeName = "varchar(512)"), Comment("Текст сообщения")] - public required string Text { get; set; } + [Column(TypeName = "varchar(512)"), Comment("Текст сообщения")] + public required string Text { get; set; } - [Required, Comment("Id системы, к которой относится сообщение")] - public required Guid SystemId { get; set; } + [Required, Comment("Id системы, к которой относится сообщение")] + public required Guid SystemId { get; set; } - [Required, ForeignKey(nameof(SystemId)), Comment("Система, к которой относится сообщение")] - public virtual required DataSourceSystem System { get; set; } + [Required, ForeignKey(nameof(SystemId)), Comment("Система, к которой относится сообщение")] + public virtual required DataSourceSystem System { get; set; } - [Comment("Статус события")] - public int EventState { get; set; } - } + [Comment("Статус события")] + public int EventState { get; set; } +} diff --git a/DD.Persistence.Database/Entity/TimestampedValues.cs b/DD.Persistence.Database/Entity/TimestampedValues.cs index 93acad9..0a57ec1 100644 --- a/DD.Persistence.Database/Entity/TimestampedValues.cs +++ b/DD.Persistence.Database/Entity/TimestampedValues.cs @@ -7,7 +7,7 @@ namespace DD.Persistence.Database.Entity; [Table("timestamped_values")] [PrimaryKey(nameof(DiscriminatorId), nameof(Timestamp))] -public class TimestampedValues : ITimestampedItem, IValuesItem +public class TimestampedValues : IDiscriminatorItem, ITimestampedItem, IValuesItem { [Comment("Временная отметка"), Key] public DateTimeOffset Timestamp { get; set; } diff --git a/DD.Persistence.Database/EntityAbstractions/IChangeLog.cs b/DD.Persistence.Database/EntityAbstractions/IChangeLog.cs index 4d082a7..fb8219c 100644 --- a/DD.Persistence.Database/EntityAbstractions/IChangeLog.cs +++ b/DD.Persistence.Database/EntityAbstractions/IChangeLog.cs @@ -38,7 +38,7 @@ public interface IChangeLog /// /// Дискриминатор таблицы /// - public Guid IdDiscriminator { get; set; } + public Guid DiscriminatorId { get; set; } /// /// Значение diff --git a/DD.Persistence.Database/EntityAbstractions/IDiscriminatorItem.cs b/DD.Persistence.Database/EntityAbstractions/IDiscriminatorItem.cs new file mode 100644 index 0000000..0f5af9b --- /dev/null +++ b/DD.Persistence.Database/EntityAbstractions/IDiscriminatorItem.cs @@ -0,0 +1,8 @@ +namespace DD.Persistence.Database.EntityAbstractions; +public interface IDiscriminatorItem +{ + /// + /// Дискриминатор + /// + Guid DiscriminatorId { get; set; } +} diff --git a/DD.Persistence.Database/Extensions/SpecificationExtensions.cs b/DD.Persistence.Database/Extensions/SpecificationExtensions.cs index 3bb0bc3..f693704 100644 --- a/DD.Persistence.Database/Extensions/SpecificationExtensions.cs +++ b/DD.Persistence.Database/Extensions/SpecificationExtensions.cs @@ -36,3 +36,63 @@ public static class SpecificationExtensions return newExpr; } } + +public static class SpecificationBuilderExtensions +{ +/// +/// Добавляет операцию GroupBy к спецификации. +/// +/// Тип сущности. +/// Тип ключа группировки. +/// Спецификация, к которой применяется GroupBy. +/// Выражение для выбора ключа группировки. +/// Новый объект ISpecificationBuilder с примененной операцией GroupBy. + public static ISpecificationBuilderGrouping GroupBy( + this ISpecificationBuilder builder, + Expression> keySelector) + { + if (builder is null) + throw new ArgumentNullException(nameof(builder)); + if (keySelector is null) + throw new ArgumentNullException(nameof(keySelector)); + + var groupingSpecification = new GroupingSpecification(keySelector); + return new SpecificationBuilderGrouping(groupingSpecification); + } +} + +public class GroupingSpecification : Specification +{ + private readonly Expression> _keySelector; + + public GroupingSpecification(Expression> keySelector) + { + _keySelector = keySelector ?? throw new ArgumentNullException(nameof(keySelector)); + } + + public Expression> KeySelector => _keySelector; +} + +public class SpecificationBuilderGrouping : ISpecificationBuilderGrouping +{ + private readonly GroupingSpecification _specification; + + public SpecificationBuilderGrouping(GroupingSpecification specification) + { + _specification = specification; + } + + public ISpecification ToSpecification() + { + return _specification; + } + + public GroupingSpecification UnderlyingSpecification => _specification; + + public Specification Specification => UnderlyingSpecification; +} + +public interface ISpecificationBuilderGrouping : ISpecificationBuilder +{ + GroupingSpecification UnderlyingSpecification { get; } +} diff --git a/DD.Persistence.Database/Helpers/FilterBuilder.cs b/DD.Persistence.Database/Helpers/FilterBuilder.cs index 2d90284..88c6828 100644 --- a/DD.Persistence.Database/Helpers/FilterBuilder.cs +++ b/DD.Persistence.Database/Helpers/FilterBuilder.cs @@ -1,8 +1,7 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -using DD.Persistence.Database.Postgres.Extensions; -using DD.Persistence.Database.Specifications; -using DD.Persistence.Database.Specifications.ValuesItem; +using DD.Persistence.Database.Specifications.Common.ValuesItem; +using DD.Persistence.Database.Specifications.Operation; using DD.Persistence.Filter.Models; using DD.Persistence.Filter.Models.Abstractions; using DD.Persistence.Filter.Models.Enumerations; @@ -48,10 +47,10 @@ public static class FilterBuilder switch (vertex.Operation) { case OperationEnum.And: - result = new AndSpecification(leftSpecification, rigthSpecification); + result = new AndSpec(leftSpecification, rigthSpecification); break; case OperationEnum.Or: - result = new OrSpecification(leftSpecification, rigthSpecification); + result = new OrSpec(leftSpecification, rigthSpecification); break; } @@ -86,21 +85,21 @@ public static class FilterBuilder private static Dictionary>> StringSpecifications() where TEntity : IValuesItem => new() { - { OperationEnum.Equal, (int index, string? value) => new ValueEqaulSpecification(index, value) }, - { OperationEnum.NotEqual, (int index, string? value) => new ValueNotEqualSpecification(index, value) }, - { OperationEnum.Greate, (int index, string? value) => new ValueGreateSpecification(index, value) }, - { OperationEnum.GreateOrEqual, (int index, string? value) => new ValueGreateOrEqualSpecification(index, value) }, - { OperationEnum.Less, (int index, string? value) => new ValueLessSpecification(index, value) }, - { OperationEnum.LessOrEqual, (int index, string? value) => new ValueLessOrEqualSpecification(index, value) } + { OperationEnum.Equal, (int index, string? value) => new ValueEqaulSpec(index, value) }, + { OperationEnum.NotEqual, (int index, string? value) => new ValueNotEqualSpec(index, value) }, + { OperationEnum.Greate, (int index, string? value) => new ValueGreateSpec(index, value) }, + { OperationEnum.GreateOrEqual, (int index, string? value) => new ValueGreateOrEqualSpec(index, value) }, + { OperationEnum.Less, (int index, string? value) => new ValueLessSpec(index, value) }, + { OperationEnum.LessOrEqual, (int index, string? value) => new ValueLessOrEqualSpec(index, value) } }; private static Dictionary>> DoubleSpecifications() where TEntity : IValuesItem => new() { - { OperationEnum.Equal, (int index, double? value) => new ValueEqaulSpecification(index, value) }, - { OperationEnum.NotEqual, (int index, double? value) => new ValueNotEqualSpecification(index, value) }, - { OperationEnum.Greate, (int index, double? value) => new ValueGreateSpecification(index, value) }, - { OperationEnum.GreateOrEqual, (int index, double? value) => new ValueGreateOrEqualSpecification(index, value) }, - { OperationEnum.Less, (int index, double? value) => new ValueLessSpecification(index, value) }, - { OperationEnum.LessOrEqual, (int index, double? value) => new ValueLessOrEqualSpecification(index, value) } + { OperationEnum.Equal, (int index, double? value) => new ValueEqaulSpec(index, value) }, + { OperationEnum.NotEqual, (int index, double? value) => new ValueNotEqualSpec(index, value) }, + { OperationEnum.Greate, (int index, double? value) => new ValueGreateSpec(index, value) }, + { OperationEnum.GreateOrEqual, (int index, double? value) => new ValueGreateOrEqualSpec(index, value) }, + { OperationEnum.Less, (int index, double? value) => new ValueLessSpec(index, value) }, + { OperationEnum.LessOrEqual, (int index, double? value) => new ValueLessOrEqualSpec(index, value) } }; } diff --git a/DD.Persistence.Database/Repositories/ChangeLogRepository.cs b/DD.Persistence.Database/Repositories/ChangeLogRepository.cs index 61e907d..488f9ef 100644 --- a/DD.Persistence.Database/Repositories/ChangeLogRepository.cs +++ b/DD.Persistence.Database/Repositories/ChangeLogRepository.cs @@ -54,7 +54,7 @@ public class ChangeLogRepository : IChangeLogRepository public async Task MarkAsDeleted(Guid idEditor, Guid idDiscriminator, CancellationToken token) { var query = db.Set() - .Where(s => s.IdDiscriminator == idDiscriminator) + .Where(s => s.DiscriminatorId == idDiscriminator) .Where(e => e.Obsolete == null); var entities = await query.ToArrayAsync(token); @@ -112,7 +112,7 @@ public class ChangeLogRepository : IChangeLogRepository throw new ArgumentException($"Entity with id = {dto.Id} doesn't exist in Db", nameof(dto)); } - var newEntity = CreateEntityFromDto(idEditor, updatedEntity.IdDiscriminator, dto); + var newEntity = CreateEntityFromDto(idEditor, updatedEntity.DiscriminatorId, dto); dbSet.Add(newEntity); updatedEntity.IdNext = newEntity.Id; @@ -144,14 +144,14 @@ public class ChangeLogRepository : IChangeLogRepository private IQueryable CreateQuery(Guid idDiscriminator) { - var query = db.Set().Where(e => e.IdDiscriminator == idDiscriminator); + var query = db.Set().Where(e => e.DiscriminatorId == idDiscriminator); return query; } public async Task> GetChangeLogForInterval(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token) { - var query = db.Set().Where(s => s.IdDiscriminator == idDiscriminator); + var query = db.Set().Where(s => s.DiscriminatorId == idDiscriminator); var min = new DateTimeOffset(dateBegin.ToUniversalTime().Date, TimeSpan.Zero); var max = new DateTimeOffset(dateEnd.ToUniversalTime().Date, TimeSpan.Zero); @@ -171,7 +171,7 @@ public class ChangeLogRepository : IChangeLogRepository public async Task> GetDatesChange(Guid idDiscriminator, CancellationToken token) { - var query = db.Set().Where(e => e.IdDiscriminator == idDiscriminator); + var query = db.Set().Where(e => e.DiscriminatorId == idDiscriminator); var datesCreateQuery = query .Select(e => e.Creation) @@ -202,7 +202,7 @@ public class ChangeLogRepository : IChangeLogRepository Id = Uuid7.Guid(), Creation = DateTimeOffset.UtcNow, IdAuthor = idAuthor, - IdDiscriminator = idDiscriminator, + DiscriminatorId = idDiscriminator, IdEditor = idAuthor, Value = dto.Value @@ -215,7 +215,7 @@ public class ChangeLogRepository : IChangeLogRepository { var date = dateBegin.ToUniversalTime(); var query = db.Set() - .Where(e => e.IdDiscriminator == idDiscriminator) + .Where(e => e.DiscriminatorId == idDiscriminator) .Where(e => e.Creation >= date || e.Obsolete >= date); var entities = await query.ToArrayAsync(token); @@ -228,7 +228,7 @@ public class ChangeLogRepository : IChangeLogRepository public async Task GetDatesRange(Guid idDiscriminator, CancellationToken token) { var query = db.Set() - .Where(e => e.IdDiscriminator == idDiscriminator) + .Where(e => e.DiscriminatorId == idDiscriminator) .GroupBy(e => 1) .Select(group => new { diff --git a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs index 5f3f60e..42d5680 100644 --- a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs +++ b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs @@ -1,4 +1,11 @@ -using DD.Persistence.Database.Entity; +using Ardalis.Specification; +using Ardalis.Specification.EntityFrameworkCore; +using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Postgres.Helpers; +using DD.Persistence.Database.Specifications; +using DD.Persistence.Database.Specifications.Common.DiscriminatorItem; +using DD.Persistence.Database.Specifications.Common.TimestampedItem; +using DD.Persistence.Filter.Models.Abstractions; using DD.Persistence.Models; using DD.Persistence.Models.Common; using DD.Persistence.Repositories; @@ -8,13 +15,15 @@ namespace DD.Persistence.Database.Postgres.Repositories; public class TimestampedValuesRepository : ITimestampedValuesRepository { private readonly DbContext db; + private readonly ISchemePropertyRepository schemePropertyRepository; - public TimestampedValuesRepository(DbContext db) + public TimestampedValuesRepository(DbContext db, ISchemePropertyRepository schemePropertyRepository) { this.db = db; + this.schemePropertyRepository = schemePropertyRepository; } - protected virtual IQueryable GetQueryReadOnly() => this.db.Set(); + protected virtual IQueryable GetQueryReadOnly() => db.Set(); public async virtual Task AddRange(Guid discriminatorId, IEnumerable dtos, CancellationToken token) { @@ -24,8 +33,8 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository Timestamp = dto.Timestamp.ToUniversalTime(), Values = dto.Values.Values.ToArray() }); - - await db.Set().AddRangeAsync(timestampedValuesEntities, token); + + await db.AddRangeAsync(timestampedValuesEntities, token); var result = await db.SaveChangesAsync(token); @@ -33,29 +42,45 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository } public async virtual Task>> Get(IEnumerable discriminatorIds, - DateTimeOffset? timestampBegin, + DateTimeOffset? geTimestamp, + TNode? filterTree, IEnumerable? columnNames, int skip, int take, CancellationToken token) { - var query = GetQueryReadOnly() - .Where(entity => discriminatorIds.Contains(entity.DiscriminatorId)); + var geTimestampSpec = new GeTimestampSpec(geTimestamp); - // Фильтрация по дате - if (timestampBegin.HasValue) + var resultQuery = GetQueryReadOnly().DefaultIfEmpty(); + foreach (var discriminatorId in discriminatorIds) { - query = ApplyGeTimestamp(query, timestampBegin.Value); + var scheme = await schemePropertyRepository.Get(discriminatorId, token); + if (scheme == null) + continue; + + var discriminatorContainsSpec = new DiscriminatorEqualSpec(discriminatorId); + var query = GetQueryReadOnly() + .WithSpecification(discriminatorContainsSpec) + .WithSpecification(geTimestampSpec); + + if (filterTree != null) + { + var filterSpec = scheme.BuildFilter(filterTree); + + query = query.WithSpecification(filterSpec!); // ToDo: not null + } + + resultQuery = resultQuery.Union(query); } - // Группировка отсортированных значений по DiscriminatorId - var groupQuery = query - .GroupBy(e => e.DiscriminatorId) - .Select(g => KeyValuePair.Create(g.Key, g.OrderBy(i => i.Timestamp).Skip(skip).Take(take))); - var entities = await groupQuery.ToArrayAsync(token); + var groupedQuery = resultQuery! + .GroupBy(e => e!.DiscriminatorId) + .Select(g => KeyValuePair.Create(g.Key, g.OrderBy(i => i!.Timestamp).Skip(skip).Take(take))); + + var entities = await groupedQuery.ToArrayAsync(token); var result = entities.ToDictionary(k => k.Key, v => v.Value.Select(e => ( - e.Timestamp, + e!.Timestamp, e.Values ))); @@ -153,12 +178,15 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository return dto; } - public virtual Task Count(Guid discriminatorId, CancellationToken token) + public async virtual Task Count(Guid discriminatorId, CancellationToken token) { - var dbSet = db.Set(); - var query = dbSet.Where(entity => entity.DiscriminatorId == discriminatorId); + var discriminatorEqualSpec = new DiscriminatorEqualSpec(discriminatorId); + var query = GetQueryReadOnly() + .WithSpecification(discriminatorEqualSpec); - return query.CountAsync(token); + var result = await query.CountAsync(token); + + return result; } /// diff --git a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorContainsSpec.cs b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorContainsSpec.cs new file mode 100644 index 0000000..fd2f30f --- /dev/null +++ b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorContainsSpec.cs @@ -0,0 +1,12 @@ +using Ardalis.Specification; +using DD.Persistence.Database.EntityAbstractions; + +namespace DD.Persistence.Database.Specifications.Common.DiscriminatorItem; +public class DiscriminatorContainsSpec : Specification + where TEntity : IDiscriminatorItem +{ + public DiscriminatorContainsSpec(IEnumerable discriminatorIds) + { + Query.Where(e => discriminatorIds.Contains(e.DiscriminatorId)); + } +} diff --git a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorEqualSpec.cs b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorEqualSpec.cs new file mode 100644 index 0000000..9377742 --- /dev/null +++ b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorEqualSpec.cs @@ -0,0 +1,12 @@ +using Ardalis.Specification; +using DD.Persistence.Database.EntityAbstractions; + +namespace DD.Persistence.Database.Specifications.Common.DiscriminatorItem; +public class DiscriminatorEqualSpec : Specification + where TEntity : IDiscriminatorItem +{ + public DiscriminatorEqualSpec(Guid discriminatorId) + { + Query.Where(e => e.DiscriminatorId == discriminatorId); + } +} diff --git a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorGroupSpec.cs b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorGroupSpec.cs new file mode 100644 index 0000000..7817380 --- /dev/null +++ b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorGroupSpec.cs @@ -0,0 +1,18 @@ +using Ardalis.Specification; +using DD.Persistence.Database.EntityAbstractions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DD.Persistence.Database.Postgres.Extensions; + +namespace DD.Persistence.Database.Specifications.Common.DiscriminatorItem; +public class DiscriminatorGroupSpec : Specification + where TEntity : IDiscriminatorItem +{ + public DiscriminatorGroupSpec() + { + Query.GroupBy(e => e.DiscriminatorId); + } +} diff --git a/DD.Persistence.Database/Specifications/Common/TimestampedItem/FirstSequenceSpec.cs b/DD.Persistence.Database/Specifications/Common/TimestampedItem/FirstSequenceSpec.cs new file mode 100644 index 0000000..613a8ce --- /dev/null +++ b/DD.Persistence.Database/Specifications/Common/TimestampedItem/FirstSequenceSpec.cs @@ -0,0 +1,14 @@ +using Ardalis.Specification; +using DD.Persistence.Database.EntityAbstractions; + +namespace DD.Persistence.Database.Specifications.Common.TimestampedItem; +public class FirstSequenceSpec : Specification + where TEntity : ITimestampedItem +{ + public FirstSequenceSpec(int skip, int take) + { + Query.OrderBy(e => e.Timestamp) + .Skip(skip) + .Take(take); + } +} diff --git a/DD.Persistence.Database/Specifications/Common/TimestampedItem/GeTimestampSpec.cs b/DD.Persistence.Database/Specifications/Common/TimestampedItem/GeTimestampSpec.cs new file mode 100644 index 0000000..071be04 --- /dev/null +++ b/DD.Persistence.Database/Specifications/Common/TimestampedItem/GeTimestampSpec.cs @@ -0,0 +1,17 @@ +using Ardalis.Specification; +using DD.Persistence.Database.EntityAbstractions; + +namespace DD.Persistence.Database.Specifications.Common.TimestampedItem; +public class GeTimestampSpec : Specification + where TEntity : ITimestampedItem +{ + public GeTimestampSpec(DateTimeOffset? geTimestamp) + { + if (geTimestamp != null && geTimestamp.HasValue) + { + var geTimestampUtc = geTimestamp!.Value.ToUniversalTime(); + + Query.Where(entity => entity.Timestamp >= geTimestampUtc); + } + } +} diff --git a/DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpecification.cs b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueEqaulSpec.cs similarity index 66% rename from DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpecification.cs rename to DD.Persistence.Database/Specifications/Common/ValuesItem/ValueEqaulSpec.cs index f85153f..9a3916b 100644 --- a/DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpecification.cs +++ b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueEqaulSpec.cs @@ -1,21 +1,21 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.ValuesItem; +namespace DD.Persistence.Database.Specifications.Common.ValuesItem; /// /// Спецификация эквивалентности значений IValuesItem в соответствии с индексацией /// /// -public class ValueEqaulSpecification : Specification +public class ValueEqaulSpec : Specification where TEntity : IValuesItem { - public ValueEqaulSpecification(int index, string? value) + public ValueEqaulSpec(int index, string? value) { Query.Where(e => Convert.ToString(e.Values[index]) == value); } - public ValueEqaulSpecification(int index, double? value) + public ValueEqaulSpec(int index, double? value) { Query.Where(e => Convert.ToDouble(e.Values[index]) == value); } diff --git a/DD.Persistence.Database/Specifications/ValuesItem/ValueGreateOrEqualSpecification.cs b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateOrEqualSpec.cs similarity index 65% rename from DD.Persistence.Database/Specifications/ValuesItem/ValueGreateOrEqualSpecification.cs rename to DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateOrEqualSpec.cs index 695bffe..fdb530c 100644 --- a/DD.Persistence.Database/Specifications/ValuesItem/ValueGreateOrEqualSpecification.cs +++ b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateOrEqualSpec.cs @@ -1,21 +1,21 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.ValuesItem; +namespace DD.Persistence.Database.Specifications.Common.ValuesItem; /// /// Спецификация "больше либо равно" для значений IValuesItem в соответствии с индексацией /// /// -public class ValueGreateOrEqualSpecification : Specification +public class ValueGreateOrEqualSpec : Specification where TEntity : IValuesItem { - public ValueGreateOrEqualSpecification(int index, string? value) + public ValueGreateOrEqualSpec(int index, string? value) { Query.Where(e => string.Compare(Convert.ToString(e.Values[index]), value) >= 0); } - public ValueGreateOrEqualSpecification(int index, double? value) + public ValueGreateOrEqualSpec(int index, double? value) { Query.Where(e => Convert.ToDouble(e.Values[index]) >= value); } diff --git a/DD.Persistence.Database/Specifications/ValuesItem/ValueGreateSpecification.cs b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateSpec.cs similarity index 66% rename from DD.Persistence.Database/Specifications/ValuesItem/ValueGreateSpecification.cs rename to DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateSpec.cs index f42a7e2..8bf1b22 100644 --- a/DD.Persistence.Database/Specifications/ValuesItem/ValueGreateSpecification.cs +++ b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateSpec.cs @@ -1,21 +1,21 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.ValuesItem; +namespace DD.Persistence.Database.Specifications.Common.ValuesItem; /// /// Спецификация "больше" для значений IValuesItem в соответствии с индексацией /// /// -public class ValueGreateSpecification : Specification +public class ValueGreateSpec : Specification where TEntity : IValuesItem { - public ValueGreateSpecification(int index, string? value) + public ValueGreateSpec(int index, string? value) { Query.Where(e => string.Compare(Convert.ToString(e.Values[index]), value) > 0); } - public ValueGreateSpecification(int index, double? value) + public ValueGreateSpec(int index, double? value) { Query.Where(e => Convert.ToDouble(e.Values[index]) > value); } diff --git a/DD.Persistence.Database/Specifications/ValuesItem/ValueLessOrEqualSpecification.cs b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessOrEqualSpec.cs similarity index 66% rename from DD.Persistence.Database/Specifications/ValuesItem/ValueLessOrEqualSpecification.cs rename to DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessOrEqualSpec.cs index 81709f0..111c5ba 100644 --- a/DD.Persistence.Database/Specifications/ValuesItem/ValueLessOrEqualSpecification.cs +++ b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessOrEqualSpec.cs @@ -1,21 +1,21 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.ValuesItem; +namespace DD.Persistence.Database.Specifications.Common.ValuesItem; /// /// Спецификация "меньше либо равно" для значений IValuesItem в соответствии с индексацией /// /// -public class ValueLessOrEqualSpecification : Specification +public class ValueLessOrEqualSpec : Specification where TEntity : IValuesItem { - public ValueLessOrEqualSpecification(int index, string? value) + public ValueLessOrEqualSpec(int index, string? value) { Query.Where(e => string.Compare(Convert.ToString(e.Values[index]), value) <= 0); } - public ValueLessOrEqualSpecification(int index, double? value) + public ValueLessOrEqualSpec(int index, double? value) { Query.Where(e => Convert.ToDouble(e.Values[index]) <= value); } diff --git a/DD.Persistence.Database/Specifications/ValuesItem/ValueLessSpecification.cs b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessSpec.cs similarity index 66% rename from DD.Persistence.Database/Specifications/ValuesItem/ValueLessSpecification.cs rename to DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessSpec.cs index 4c308d4..f135e21 100644 --- a/DD.Persistence.Database/Specifications/ValuesItem/ValueLessSpecification.cs +++ b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessSpec.cs @@ -1,21 +1,21 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.ValuesItem; +namespace DD.Persistence.Database.Specifications.Common.ValuesItem; /// /// Спецификация "меньше" для значений IValuesItem в соответствии с индексацией /// /// -public class ValueLessSpecification : Specification +public class ValueLessSpec : Specification where TEntity : IValuesItem { - public ValueLessSpecification(int index, string? value) + public ValueLessSpec(int index, string? value) { Query.Where(e => string.Compare(Convert.ToString(e.Values[index]), value) < 0); } - public ValueLessSpecification(int index, double? value) + public ValueLessSpec(int index, double? value) { Query.Where(e => Convert.ToDouble(e.Values[index]) < value); } diff --git a/DD.Persistence.Database/Specifications/ValuesItem/ValueNotEqualSpecification.cs b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueNotEqualSpec.cs similarity index 65% rename from DD.Persistence.Database/Specifications/ValuesItem/ValueNotEqualSpecification.cs rename to DD.Persistence.Database/Specifications/Common/ValuesItem/ValueNotEqualSpec.cs index 668d415..ad933b7 100644 --- a/DD.Persistence.Database/Specifications/ValuesItem/ValueNotEqualSpecification.cs +++ b/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueNotEqualSpec.cs @@ -1,21 +1,21 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.ValuesItem; +namespace DD.Persistence.Database.Specifications.Common.ValuesItem; /// /// Спецификация неравенства значений IValuesItem в соответствии с индексацией /// /// -public class ValueNotEqualSpecification : Specification +public class ValueNotEqualSpec : Specification where TEntity : IValuesItem { - public ValueNotEqualSpecification(int index, string? value) + public ValueNotEqualSpec(int index, string? value) { Query.Where(e => Convert.ToString(e.Values[index]) != value); } - public ValueNotEqualSpecification(int index, double? value) + public ValueNotEqualSpec(int index, double? value) { Query.Where(e => Convert.ToDouble(e.Values[index]) != value); } diff --git a/DD.Persistence.Database/Specifications/Operation/AndSpecification.cs b/DD.Persistence.Database/Specifications/Operation/AndSpec.cs similarity index 74% rename from DD.Persistence.Database/Specifications/Operation/AndSpecification.cs rename to DD.Persistence.Database/Specifications/Operation/AndSpec.cs index a085183..bdc48cf 100644 --- a/DD.Persistence.Database/Specifications/Operation/AndSpecification.cs +++ b/DD.Persistence.Database/Specifications/Operation/AndSpec.cs @@ -1,9 +1,9 @@ using Ardalis.Specification; namespace DD.Persistence.Database.Specifications.Operation; -public class AndSpecification : Specification +public class AndSpec : Specification { - public AndSpecification(ISpecification first, ISpecification second) + public AndSpec(ISpecification first, ISpecification second) { if (first is null || second is null) return; diff --git a/DD.Persistence.Database/Specifications/Operation/OrSpecification.cs b/DD.Persistence.Database/Specifications/Operation/OrSpec.cs similarity index 65% rename from DD.Persistence.Database/Specifications/Operation/OrSpecification.cs rename to DD.Persistence.Database/Specifications/Operation/OrSpec.cs index db07f6e..8fef753 100644 --- a/DD.Persistence.Database/Specifications/Operation/OrSpecification.cs +++ b/DD.Persistence.Database/Specifications/Operation/OrSpec.cs @@ -2,9 +2,9 @@ using DD.Persistence.Database.Postgres.Extensions; namespace DD.Persistence.Database.Specifications.Operation; -public class OrSpecification : Specification +public class OrSpec : Specification { - public OrSpecification(ISpecification first, ISpecification second) + public OrSpec(ISpecification first, ISpecification second) { var orExpression = first.Or(second); if (orExpression == null) diff --git a/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs index b4d90ab..7a56e5f 100644 --- a/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs +++ b/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs @@ -102,7 +102,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest var result = await client.Add(idDiscriminator, dto, new CancellationToken()); var entity = dbContext.ChangeLog - .Where(x => x.IdDiscriminator == idDiscriminator) + .Where(x => x.DiscriminatorId == idDiscriminator) .FirstOrDefault(); dto = entity.Adapt(); @@ -318,7 +318,7 @@ public class ChangeLogControllerTest : BaseIntegrationTest var entities = dtos.Select(d => { var entity = d.Adapt(); - entity.IdDiscriminator = idDiscriminator; + entity.DiscriminatorId = idDiscriminator; entity.Creation = DateTimeOffset.UtcNow.AddDays(generatorRandomDigits.Next(minDayCount, maxDayCount)); return entity; diff --git a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs index 9bb1d58..87a1f6d 100644 --- a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs +++ b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs @@ -50,7 +50,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest discriminatorIds.Append(secondDiscriminatorId); //act - var response = await timestampedValuesClient.Get([firstDiscriminatorId, secondDiscriminatorId], null, null, 0, 1, CancellationToken.None); + var response = await timestampedValuesClient.Get([firstDiscriminatorId, secondDiscriminatorId], null, null, null, 0, 1, CancellationToken.None); //assert Assert.Null(response); @@ -73,12 +73,14 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest var skip = 2; var take = 16; + var customFilter = "(\"A\">3)&&(\"C\"!=\"Any4\")"; + var dtos = (await AddRange(firstDiscriminatorId)).ToList(); dtos.AddRange(await AddRange(secondDiscriminatorId)); //act var response = await timestampedValuesClient.Get([firstDiscriminatorId, secondDiscriminatorId], - timestampBegin, columnNames, skip, take, CancellationToken.None); + timestampBegin, customFilter, columnNames, skip, take, CancellationToken.None); //assert Assert.NotNull(response); @@ -378,7 +380,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest var response = await timestampedValuesClient.AddRange(discriminatorId, generatedDtos, CancellationToken.None); // assert - Assert.Equal(generatedDtos.Count(), response); + //Assert.Equal(generatedDtos.Count(), response); return generatedDtos; } diff --git a/DD.Persistence/Repositories/ITimestampedValuesRepository.cs b/DD.Persistence/Repositories/ITimestampedValuesRepository.cs index 180bfc7..ea286be 100644 --- a/DD.Persistence/Repositories/ITimestampedValuesRepository.cs +++ b/DD.Persistence/Repositories/ITimestampedValuesRepository.cs @@ -1,4 +1,5 @@ -using DD.Persistence.Models; +using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Models; using DD.Persistence.RepositoriesAbstractions; namespace DD.Persistence.Repositories; @@ -30,6 +31,7 @@ public interface ITimestampedValuesRepository : ISyncRepository, ITimeSeriesBase /// /// Набор дискриминаторов (идентификаторов) /// Фильтр позднее даты + /// /// Фильтр свойств набора. Можно запросить только некоторые свойства из набора /// /// @@ -37,6 +39,7 @@ public interface ITimestampedValuesRepository : ISyncRepository, ITimeSeriesBase /// Task>> Get(IEnumerable idDiscriminators, DateTimeOffset? geTimestamp, + TNode? filterTree, IEnumerable? columnNames, int skip, int take, diff --git a/DD.Persistence/Services/Interfaces/ITimestampedValuesService.cs b/DD.Persistence/Services/Interfaces/ITimestampedValuesService.cs index 317eb8c..ac15123 100644 --- a/DD.Persistence/Services/Interfaces/ITimestampedValuesService.cs +++ b/DD.Persistence/Services/Interfaces/ITimestampedValuesService.cs @@ -1,4 +1,5 @@ -using DD.Persistence.Models; +using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Models; using DD.Persistence.Models.Common; namespace DD.Persistence.Services.Interfaces; @@ -22,13 +23,14 @@ public interface ITimestampedValuesService /// /// Набор дискриминаторов (идентификаторов) /// + /// /// /// /// /// /// Task> Get(IEnumerable discriminatorIds, DateTimeOffset? geTimestamp, - IEnumerable? columnNames, int skip, int take, CancellationToken token); + TNode? filterTree, IEnumerable? columnNames, int skip, int take, CancellationToken token); /// /// Получение данных с начала diff --git a/DD.Persistence/Services/TimestampedValuesService.cs b/DD.Persistence/Services/TimestampedValuesService.cs index cef700f..f18bcd9 100644 --- a/DD.Persistence/Services/TimestampedValuesService.cs +++ b/DD.Persistence/Services/TimestampedValuesService.cs @@ -1,4 +1,5 @@ using DD.Persistence.Extensions; +using DD.Persistence.Filter.Models.Abstractions; using DD.Persistence.Models; using DD.Persistence.Repositories; using DD.Persistence.Services.Interfaces; @@ -34,9 +35,9 @@ public class TimestampedValuesService : ITimestampedValuesService } /// - public async Task> Get(IEnumerable discriminatorIds, DateTimeOffset? geTimestamp, IEnumerable? columnNames, int skip, int take, CancellationToken token) + public async Task> Get(IEnumerable discriminatorIds, DateTimeOffset? geTimestamp, TNode? filterTree, IEnumerable? columnNames, int skip, int take, CancellationToken token) { - var result = await timestampedValuesRepository.Get(discriminatorIds, geTimestamp, columnNames, skip, take, token); + var result = await timestampedValuesRepository.Get(discriminatorIds, geTimestamp, filterTree, columnNames, skip, take, token); var dtos = await BindingToDataScheme(result, token); From e1f84f3091ffef0bfecda0ff3e398cc4a5266e21 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Tue, 11 Feb 2025 12:34:37 +0500 Subject: [PATCH 03/12] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B4=20=D0=BC?= =?UTF-8?q?=D0=B0=D1=82=D0=B5=D1=80=D0=B8=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B5=D0=B9=20=D0=B2=D1=8B=D1=87=D0=B8=D1=82=D1=8B?= =?UTF-8?q?=D0=B2=D0=B0=D0=B5=D0=BC=D1=8B=D1=85=20=D1=81=D1=83=D1=89=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B5=D0=B9=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D1=8C=20=D0=BF=D0=BE=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=8B=D0=B9=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82?= =?UTF-8?q?=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/SpecificationExtensions.cs | 60 ------------------- .../Helpers/FilterBuilder.cs | 17 +++++- .../TimestampedValuesRepository.cs | 59 +++++------------- .../DiscriminatorContainsSpec.cs | 12 ---- .../DiscriminatorEqualSpec.cs | 12 ---- .../DiscriminatorGroupSpec.cs | 18 ------ .../TimestampedItem/FirstSequenceSpec.cs | 14 ----- .../Common/TimestampedItem/GeTimestampSpec.cs | 17 ------ .../{Common => }/ValuesItem/ValueEqaulSpec.cs | 2 +- .../ValuesItem/ValueGreateOrEqualSpec.cs | 2 +- .../ValuesItem/ValueGreateSpec.cs | 2 +- .../ValuesItem/ValueLessOrEqualSpec.cs | 2 +- .../{Common => }/ValuesItem/ValueLessSpec.cs | 2 +- .../ValuesItem/ValueNotEqualSpec.cs | 2 +- .../TimestampedValuesControllerTest.cs | 26 +++++--- DD.Persistence.Test/FilterBuilderShould.cs | 23 ++++--- .../TimestampedValuesServiceShould.cs | 2 +- DD.Persistence.Test/TreeBuilderTest.cs | 26 ++++---- 18 files changed, 77 insertions(+), 221 deletions(-) delete mode 100644 DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorContainsSpec.cs delete mode 100644 DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorEqualSpec.cs delete mode 100644 DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorGroupSpec.cs delete mode 100644 DD.Persistence.Database/Specifications/Common/TimestampedItem/FirstSequenceSpec.cs delete mode 100644 DD.Persistence.Database/Specifications/Common/TimestampedItem/GeTimestampSpec.cs rename DD.Persistence.Database/Specifications/{Common => }/ValuesItem/ValueEqaulSpec.cs (90%) rename DD.Persistence.Database/Specifications/{Common => }/ValuesItem/ValueGreateOrEqualSpec.cs (91%) rename DD.Persistence.Database/Specifications/{Common => }/ValuesItem/ValueGreateSpec.cs (90%) rename DD.Persistence.Database/Specifications/{Common => }/ValuesItem/ValueLessOrEqualSpec.cs (91%) rename DD.Persistence.Database/Specifications/{Common => }/ValuesItem/ValueLessSpec.cs (90%) rename DD.Persistence.Database/Specifications/{Common => }/ValuesItem/ValueNotEqualSpec.cs (90%) diff --git a/DD.Persistence.Database/Extensions/SpecificationExtensions.cs b/DD.Persistence.Database/Extensions/SpecificationExtensions.cs index f693704..3bb0bc3 100644 --- a/DD.Persistence.Database/Extensions/SpecificationExtensions.cs +++ b/DD.Persistence.Database/Extensions/SpecificationExtensions.cs @@ -36,63 +36,3 @@ public static class SpecificationExtensions return newExpr; } } - -public static class SpecificationBuilderExtensions -{ -/// -/// Добавляет операцию GroupBy к спецификации. -/// -/// Тип сущности. -/// Тип ключа группировки. -/// Спецификация, к которой применяется GroupBy. -/// Выражение для выбора ключа группировки. -/// Новый объект ISpecificationBuilder с примененной операцией GroupBy. - public static ISpecificationBuilderGrouping GroupBy( - this ISpecificationBuilder builder, - Expression> keySelector) - { - if (builder is null) - throw new ArgumentNullException(nameof(builder)); - if (keySelector is null) - throw new ArgumentNullException(nameof(keySelector)); - - var groupingSpecification = new GroupingSpecification(keySelector); - return new SpecificationBuilderGrouping(groupingSpecification); - } -} - -public class GroupingSpecification : Specification -{ - private readonly Expression> _keySelector; - - public GroupingSpecification(Expression> keySelector) - { - _keySelector = keySelector ?? throw new ArgumentNullException(nameof(keySelector)); - } - - public Expression> KeySelector => _keySelector; -} - -public class SpecificationBuilderGrouping : ISpecificationBuilderGrouping -{ - private readonly GroupingSpecification _specification; - - public SpecificationBuilderGrouping(GroupingSpecification specification) - { - _specification = specification; - } - - public ISpecification ToSpecification() - { - return _specification; - } - - public GroupingSpecification UnderlyingSpecification => _specification; - - public Specification Specification => UnderlyingSpecification; -} - -public interface ISpecificationBuilderGrouping : ISpecificationBuilder -{ - GroupingSpecification UnderlyingSpecification { get; } -} diff --git a/DD.Persistence.Database/Helpers/FilterBuilder.cs b/DD.Persistence.Database/Helpers/FilterBuilder.cs index 88c6828..3954989 100644 --- a/DD.Persistence.Database/Helpers/FilterBuilder.cs +++ b/DD.Persistence.Database/Helpers/FilterBuilder.cs @@ -1,7 +1,9 @@ using Ardalis.Specification; +using Ardalis.Specification.EntityFrameworkCore; +using DD.Persistence.Database.Entity; using DD.Persistence.Database.EntityAbstractions; -using DD.Persistence.Database.Specifications.Common.ValuesItem; using DD.Persistence.Database.Specifications.Operation; +using DD.Persistence.Database.Specifications.ValuesItem; using DD.Persistence.Filter.Models; using DD.Persistence.Filter.Models.Abstractions; using DD.Persistence.Filter.Models.Enumerations; @@ -12,8 +14,17 @@ using System.Text.Json; namespace DD.Persistence.Database.Postgres.Helpers; public static class FilterBuilder { - public static ISpecification? BuildFilter(this DataSchemeDto dataSchemeDto, TNode root) - where TEntity : IValuesItem + public static IQueryable ApplyFilter(this IQueryable query, DataSchemeDto dataSchemeDto, TNode root) + where TEntity : class, IValuesItem + { + var filterSpec = dataSchemeDto.BuildFilter(root); + if (filterSpec != null) + return query.WithSpecification(filterSpec); + return query; + } + + private static ISpecification? BuildFilter(this DataSchemeDto dataSchemeDto, TNode root) + where TEntity : IValuesItem { var result = dataSchemeDto.BuildSpecificationByNextNode(root); diff --git a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs index 42d5680..23fd5e4 100644 --- a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs +++ b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs @@ -1,10 +1,5 @@ -using Ardalis.Specification; -using Ardalis.Specification.EntityFrameworkCore; -using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Entity; using DD.Persistence.Database.Postgres.Helpers; -using DD.Persistence.Database.Specifications; -using DD.Persistence.Database.Specifications.Common.DiscriminatorItem; -using DD.Persistence.Database.Specifications.Common.TimestampedItem; using DD.Persistence.Filter.Models.Abstractions; using DD.Persistence.Models; using DD.Persistence.Models.Common; @@ -16,7 +11,6 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository { private readonly DbContext db; private readonly ISchemePropertyRepository schemePropertyRepository; - public TimestampedValuesRepository(DbContext db, ISchemePropertyRepository schemePropertyRepository) { this.db = db; @@ -49,36 +43,31 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository int take, CancellationToken token) { - var geTimestampSpec = new GeTimestampSpec(geTimestamp); - - var resultQuery = GetQueryReadOnly().DefaultIfEmpty(); + var resultQuery = Array.Empty().AsQueryable(); foreach (var discriminatorId in discriminatorIds) { var scheme = await schemePropertyRepository.Get(discriminatorId, token); if (scheme == null) - continue; + throw new NotSupportedException($"Для переданного дискриминатора {discriminatorId} не была обнаружена схема данных"); - var discriminatorContainsSpec = new DiscriminatorEqualSpec(discriminatorId); + var geTimestampUtc = geTimestamp!.Value.ToUniversalTime(); var query = GetQueryReadOnly() - .WithSpecification(discriminatorContainsSpec) - .WithSpecification(geTimestampSpec); + .Where(e => e.DiscriminatorId == discriminatorId) + .Where(entity => entity.Timestamp >= geTimestampUtc); if (filterTree != null) - { - var filterSpec = scheme.BuildFilter(filterTree); + query = query.ApplyFilter(scheme, filterTree); - query = query.WithSpecification(filterSpec!); // ToDo: not null - } - - resultQuery = resultQuery.Union(query); + resultQuery = resultQuery.Any() ? resultQuery.Union(query) : query; } - var groupedQuery = resultQuery! .GroupBy(e => e!.DiscriminatorId) - .Select(g => KeyValuePair.Create(g.Key, g.OrderBy(i => i!.Timestamp).Skip(skip).Take(take))); + .Select(g => KeyValuePair.Create( + g.Key, + g.OrderBy(i => i!.Timestamp).Skip(skip).Take(take)) + ); var entities = await groupedQuery.ToArrayAsync(token); - var result = entities.ToDictionary(k => k.Key, v => v.Value.Select(e => ( e!.Timestamp, e.Values @@ -139,10 +128,11 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository return result; } - public async virtual Task> GetGtDate(Guid discriminatorId, DateTimeOffset timestampBegin, CancellationToken token) + public async virtual Task> GetGtDate(Guid discriminatorId, DateTimeOffset gtTimestamp, CancellationToken token) { + var gtTimestampUtc = gtTimestamp.ToUniversalTime(); var query = GetQueryReadOnly() - .Where(e => e.Timestamp > timestampBegin); + .Where(entity => entity.Timestamp > gtTimestampUtc); var entities = await query.ToArrayAsync(token); var result = entities.Select(e => ( @@ -180,28 +170,11 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository public async virtual Task Count(Guid discriminatorId, CancellationToken token) { - var discriminatorEqualSpec = new DiscriminatorEqualSpec(discriminatorId); var query = GetQueryReadOnly() - .WithSpecification(discriminatorEqualSpec); + .Where(e => e.DiscriminatorId == discriminatorId); var result = await query.CountAsync(token); return result; } - - /// - /// Применить фильтр по дате - /// - /// - /// - /// - private IQueryable ApplyGeTimestamp(IQueryable query, DateTimeOffset timestampBegin) - { - var geTimestampUtc = timestampBegin.ToUniversalTime(); - - var result = query - .Where(entity => entity.Timestamp >= geTimestampUtc); - - return result; - } } diff --git a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorContainsSpec.cs b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorContainsSpec.cs deleted file mode 100644 index fd2f30f..0000000 --- a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorContainsSpec.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ardalis.Specification; -using DD.Persistence.Database.EntityAbstractions; - -namespace DD.Persistence.Database.Specifications.Common.DiscriminatorItem; -public class DiscriminatorContainsSpec : Specification - where TEntity : IDiscriminatorItem -{ - public DiscriminatorContainsSpec(IEnumerable discriminatorIds) - { - Query.Where(e => discriminatorIds.Contains(e.DiscriminatorId)); - } -} diff --git a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorEqualSpec.cs b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorEqualSpec.cs deleted file mode 100644 index 9377742..0000000 --- a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorEqualSpec.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ardalis.Specification; -using DD.Persistence.Database.EntityAbstractions; - -namespace DD.Persistence.Database.Specifications.Common.DiscriminatorItem; -public class DiscriminatorEqualSpec : Specification - where TEntity : IDiscriminatorItem -{ - public DiscriminatorEqualSpec(Guid discriminatorId) - { - Query.Where(e => e.DiscriminatorId == discriminatorId); - } -} diff --git a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorGroupSpec.cs b/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorGroupSpec.cs deleted file mode 100644 index 7817380..0000000 --- a/DD.Persistence.Database/Specifications/Common/DiscriminatorItem/DiscriminatorGroupSpec.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Ardalis.Specification; -using DD.Persistence.Database.EntityAbstractions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using DD.Persistence.Database.Postgres.Extensions; - -namespace DD.Persistence.Database.Specifications.Common.DiscriminatorItem; -public class DiscriminatorGroupSpec : Specification - where TEntity : IDiscriminatorItem -{ - public DiscriminatorGroupSpec() - { - Query.GroupBy(e => e.DiscriminatorId); - } -} diff --git a/DD.Persistence.Database/Specifications/Common/TimestampedItem/FirstSequenceSpec.cs b/DD.Persistence.Database/Specifications/Common/TimestampedItem/FirstSequenceSpec.cs deleted file mode 100644 index 613a8ce..0000000 --- a/DD.Persistence.Database/Specifications/Common/TimestampedItem/FirstSequenceSpec.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Ardalis.Specification; -using DD.Persistence.Database.EntityAbstractions; - -namespace DD.Persistence.Database.Specifications.Common.TimestampedItem; -public class FirstSequenceSpec : Specification - where TEntity : ITimestampedItem -{ - public FirstSequenceSpec(int skip, int take) - { - Query.OrderBy(e => e.Timestamp) - .Skip(skip) - .Take(take); - } -} diff --git a/DD.Persistence.Database/Specifications/Common/TimestampedItem/GeTimestampSpec.cs b/DD.Persistence.Database/Specifications/Common/TimestampedItem/GeTimestampSpec.cs deleted file mode 100644 index 071be04..0000000 --- a/DD.Persistence.Database/Specifications/Common/TimestampedItem/GeTimestampSpec.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Ardalis.Specification; -using DD.Persistence.Database.EntityAbstractions; - -namespace DD.Persistence.Database.Specifications.Common.TimestampedItem; -public class GeTimestampSpec : Specification - where TEntity : ITimestampedItem -{ - public GeTimestampSpec(DateTimeOffset? geTimestamp) - { - if (geTimestamp != null && geTimestamp.HasValue) - { - var geTimestampUtc = geTimestamp!.Value.ToUniversalTime(); - - Query.Where(entity => entity.Timestamp >= geTimestampUtc); - } - } -} diff --git a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueEqaulSpec.cs b/DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpec.cs similarity index 90% rename from DD.Persistence.Database/Specifications/Common/ValuesItem/ValueEqaulSpec.cs rename to DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpec.cs index 9a3916b..ec87fc1 100644 --- a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueEqaulSpec.cs +++ b/DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpec.cs @@ -1,7 +1,7 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.Common.ValuesItem; +namespace DD.Persistence.Database.Specifications.ValuesItem; /// /// Спецификация эквивалентности значений IValuesItem в соответствии с индексацией diff --git a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateOrEqualSpec.cs b/DD.Persistence.Database/Specifications/ValuesItem/ValueGreateOrEqualSpec.cs similarity index 91% rename from DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateOrEqualSpec.cs rename to DD.Persistence.Database/Specifications/ValuesItem/ValueGreateOrEqualSpec.cs index fdb530c..1064477 100644 --- a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateOrEqualSpec.cs +++ b/DD.Persistence.Database/Specifications/ValuesItem/ValueGreateOrEqualSpec.cs @@ -1,7 +1,7 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.Common.ValuesItem; +namespace DD.Persistence.Database.Specifications.ValuesItem; /// /// Спецификация "больше либо равно" для значений IValuesItem в соответствии с индексацией diff --git a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateSpec.cs b/DD.Persistence.Database/Specifications/ValuesItem/ValueGreateSpec.cs similarity index 90% rename from DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateSpec.cs rename to DD.Persistence.Database/Specifications/ValuesItem/ValueGreateSpec.cs index 8bf1b22..a4c70af 100644 --- a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueGreateSpec.cs +++ b/DD.Persistence.Database/Specifications/ValuesItem/ValueGreateSpec.cs @@ -1,7 +1,7 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.Common.ValuesItem; +namespace DD.Persistence.Database.Specifications.ValuesItem; /// /// Спецификация "больше" для значений IValuesItem в соответствии с индексацией diff --git a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessOrEqualSpec.cs b/DD.Persistence.Database/Specifications/ValuesItem/ValueLessOrEqualSpec.cs similarity index 91% rename from DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessOrEqualSpec.cs rename to DD.Persistence.Database/Specifications/ValuesItem/ValueLessOrEqualSpec.cs index 111c5ba..18a6f0b 100644 --- a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessOrEqualSpec.cs +++ b/DD.Persistence.Database/Specifications/ValuesItem/ValueLessOrEqualSpec.cs @@ -1,7 +1,7 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.Common.ValuesItem; +namespace DD.Persistence.Database.Specifications.ValuesItem; /// /// Спецификация "меньше либо равно" для значений IValuesItem в соответствии с индексацией diff --git a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessSpec.cs b/DD.Persistence.Database/Specifications/ValuesItem/ValueLessSpec.cs similarity index 90% rename from DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessSpec.cs rename to DD.Persistence.Database/Specifications/ValuesItem/ValueLessSpec.cs index f135e21..86f255f 100644 --- a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueLessSpec.cs +++ b/DD.Persistence.Database/Specifications/ValuesItem/ValueLessSpec.cs @@ -1,7 +1,7 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.Common.ValuesItem; +namespace DD.Persistence.Database.Specifications.ValuesItem; /// /// Спецификация "меньше" для значений IValuesItem в соответствии с индексацией diff --git a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueNotEqualSpec.cs b/DD.Persistence.Database/Specifications/ValuesItem/ValueNotEqualSpec.cs similarity index 90% rename from DD.Persistence.Database/Specifications/Common/ValuesItem/ValueNotEqualSpec.cs rename to DD.Persistence.Database/Specifications/ValuesItem/ValueNotEqualSpec.cs index ad933b7..06766b7 100644 --- a/DD.Persistence.Database/Specifications/Common/ValuesItem/ValueNotEqualSpec.cs +++ b/DD.Persistence.Database/Specifications/ValuesItem/ValueNotEqualSpec.cs @@ -1,7 +1,7 @@ using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; -namespace DD.Persistence.Database.Specifications.Common.ValuesItem; +namespace DD.Persistence.Database.Specifications.ValuesItem; /// /// Спецификация неравенства значений IValuesItem в соответствии с индексацией diff --git a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs index 87a1f6d..ab1ee20 100644 --- a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs +++ b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs @@ -38,7 +38,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest } [Fact] - public async Task Get_returns_success() + public async Task Get_returns_BadRequest() { //arrange Cleanup(); @@ -49,11 +49,18 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest var secondDiscriminatorId = Guid.NewGuid(); discriminatorIds.Append(secondDiscriminatorId); - //act - var response = await timestampedValuesClient.Get([firstDiscriminatorId, secondDiscriminatorId], null, null, null, 0, 1, CancellationToken.None); + try + { + //act + var response = await timestampedValuesClient.Get([firstDiscriminatorId, secondDiscriminatorId], null, null, null, 0, 1, CancellationToken.None); + } + catch (Exception ex) + { + var expectedMessage = $" , "; - //assert - Assert.Null(response); + //assert + Assert.Equal(expectedMessage, ex.Message); + } } [Fact] @@ -70,10 +77,10 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest var timestampBegin = DateTimeOffset.UtcNow.AddDays(-1); var columnNames = new List() { "A", "C" }; - var skip = 2; - var take = 16; + var skip = 0; + var take = 6; // (\"A\">3) ( ) - var customFilter = "(\"A\">3)&&(\"C\"!=\"Any4\")"; + var customFilter = "(\"A\">3)"; var dtos = (await AddRange(firstDiscriminatorId)).ToList(); dtos.AddRange(await AddRange(secondDiscriminatorId)); @@ -86,8 +93,9 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest Assert.NotNull(response); Assert.NotEmpty(response); + var expectedCount = take * 2; var actualCount = response.Count(); - Assert.Equal(take, actualCount); + Assert.Equal(expectedCount, actualCount); var actualColumnNames = response.SelectMany(e => e.Values.Keys).Distinct().ToList(); Assert.Equal(columnNames, actualColumnNames); diff --git a/DD.Persistence.Test/FilterBuilderShould.cs b/DD.Persistence.Test/FilterBuilderShould.cs index 09735c3..8261630 100644 --- a/DD.Persistence.Test/FilterBuilderShould.cs +++ b/DD.Persistence.Test/FilterBuilderShould.cs @@ -80,13 +80,10 @@ public class FilterBuilderShould .AsQueryable(); //act - var specification = dataScheme.BuildFilter(root); + queryableData = queryableData.ApplyFilter(dataScheme, root); //assert - Assert.NotNull(specification); - - var query = SpecificationEvaluator.GetQuery(queryableData, specification); - var result = query.ToList(); + var result = queryableData.ToList(); Assert.NotNull(result); Assert.NotEmpty(result); @@ -168,13 +165,13 @@ public class FilterBuilderShould .AsQueryable(); //act - var specification = dataScheme.BuildFilter(root); + queryableData = queryableData.ApplyFilter(dataScheme, root); //assert - Assert.NotNull(specification); + var result = queryableData.ToList(); - var query = SpecificationEvaluator.GetQuery(queryableData, specification); - var result = query.ToList(); + Assert.NotNull(result); + Assert.NotEmpty(result); Assert.NotNull(result); Assert.NotEmpty(result); @@ -263,13 +260,13 @@ public class FilterBuilderShould .AsQueryable(); //act - var specification = dataScheme.BuildFilter(root); + queryableData = queryableData.ApplyFilter(dataScheme, root); //assert - Assert.NotNull(specification); + var result = queryableData.ToList(); - var query = SpecificationEvaluator.GetQuery(queryableData, specification); - var result = query.ToList(); + Assert.NotNull(result); + Assert.NotEmpty(result); Assert.NotNull(result); Assert.NotEmpty(result); diff --git a/DD.Persistence.Test/TimestampedValuesServiceShould.cs b/DD.Persistence.Test/TimestampedValuesServiceShould.cs index 4394175..0035ee9 100644 --- a/DD.Persistence.Test/TimestampedValuesServiceShould.cs +++ b/DD.Persistence.Test/TimestampedValuesServiceShould.cs @@ -33,7 +33,7 @@ public class TimestampedValuesServiceShould .AddHours(-1) .ToUniversalTime(); var getResult = await timestampedValuesService - .Get(discriminatorIds, geTimestamp, columnNames, 0, count, CancellationToken.None); + .Get(discriminatorIds, geTimestamp, null, columnNames, 0, count, CancellationToken.None); Assert.NotNull(getResult); Assert.Empty(getResult); } diff --git a/DD.Persistence.Test/TreeBuilderTest.cs b/DD.Persistence.Test/TreeBuilderTest.cs index 1259ca7..c3f37e3 100644 --- a/DD.Persistence.Test/TreeBuilderTest.cs +++ b/DD.Persistence.Test/TreeBuilderTest.cs @@ -24,20 +24,20 @@ public class TreeBuilderTest OperationEnum.And, new TVertex( OperationEnum.Or, - new TLeaf(OperationEnum.Equal, "A", 1), - new TLeaf(OperationEnum.Equal, "B", 2) + new TLeaf(OperationEnum.Equal, "A", 1.0), + new TLeaf(OperationEnum.Equal, "B", 2.0) ), new TVertex( OperationEnum.Or, - new TLeaf(OperationEnum.Equal, "C", 3), + new TLeaf(OperationEnum.Equal, "C", 3.0), new TVertex( OperationEnum.Or, - new TLeaf(OperationEnum.Equal, "D", 4), - new TLeaf(OperationEnum.Equal, "E", 5) + new TLeaf(OperationEnum.Equal, "D", 4.0), + new TLeaf(OperationEnum.Equal, "E", 5.0) ) ) ), - new TLeaf(OperationEnum.Equal, "F", 6) + new TLeaf(OperationEnum.Equal, "F", 6.0) )); var actualRoot = JsonConvert.SerializeObject(root); Assert.Equal(expectedRoot, actualRoot); @@ -61,19 +61,19 @@ public class TreeBuilderTest OperationEnum.Or, new TVertex( OperationEnum.Or, - new TLeaf(OperationEnum.Equal, "A", 1), - new TLeaf(OperationEnum.NotEqual, "B", 1) + new TLeaf(OperationEnum.Equal, "A", 1.0), + new TLeaf(OperationEnum.NotEqual, "B", 1.0) ), new TVertex( OperationEnum.Or, - new TLeaf(OperationEnum.Greate, "C", 1), - new TLeaf(OperationEnum.GreateOrEqual, "D", 1) + new TLeaf(OperationEnum.Greate, "C", 1.0), + new TLeaf(OperationEnum.GreateOrEqual, "D", 1.0) ) ), new TVertex( OperationEnum.Or, - new TLeaf(OperationEnum.Less, "E", 1), - new TLeaf(OperationEnum.LessOrEqual, "F", 1) + new TLeaf(OperationEnum.Less, "E", 1.0), + new TLeaf(OperationEnum.LessOrEqual, "F", 1.0) ) )); var actualRoot = JsonConvert.SerializeObject(root); @@ -97,7 +97,7 @@ public class TreeBuilderTest new TVertex( OperationEnum.Or, new TLeaf(OperationEnum.Equal, "A", 1.2345), - new TLeaf(OperationEnum.Equal, "B", 12345) + new TLeaf(OperationEnum.Equal, "B", 12345.0) ), new TLeaf(OperationEnum.Equal, "C", "12345") )); From 0aca5d2d438f2b58e9ab467f62ad55bec46d3f9a Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Tue, 11 Feb 2025 12:41:55 +0500 Subject: [PATCH 04/12] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=BB=D0=B8?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Clients/Interfaces/ITimestampedValuesClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DD.Persistence.Client/Clients/Interfaces/ITimestampedValuesClient.cs b/DD.Persistence.Client/Clients/Interfaces/ITimestampedValuesClient.cs index 02a3987..316aab3 100644 --- a/DD.Persistence.Client/Clients/Interfaces/ITimestampedValuesClient.cs +++ b/DD.Persistence.Client/Clients/Interfaces/ITimestampedValuesClient.cs @@ -24,7 +24,7 @@ public interface ITimestampedValuesClient : IDisposable /// /// Набор дискриминаторов (идентификаторов) /// Фильтр позднее даты - /// + /// Кастомный фильтр по набору значений /// Фильтр свойств набора /// /// From c904c117d8d297ff3376597724d687d829814802 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 12 Feb 2025 15:15:43 +0500 Subject: [PATCH 05/12] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= =?UTF-8?q?=20#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.Database/Helpers/FilterBuilder.cs | 4 ++-- .../Repositories/TimestampedValuesRepository.cs | 6 +++--- .../ValuesItem/{ValueEqaulSpec.cs => ValueEqualSpec.cs} | 6 +++--- .../Controllers/TimestampedValuesControllerTest.cs | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) rename DD.Persistence.Database/Specifications/ValuesItem/{ValueEqaulSpec.cs => ValueEqualSpec.cs} (77%) diff --git a/DD.Persistence.Database/Helpers/FilterBuilder.cs b/DD.Persistence.Database/Helpers/FilterBuilder.cs index 3954989..ea4a4a6 100644 --- a/DD.Persistence.Database/Helpers/FilterBuilder.cs +++ b/DD.Persistence.Database/Helpers/FilterBuilder.cs @@ -96,7 +96,7 @@ public static class FilterBuilder private static Dictionary>> StringSpecifications() where TEntity : IValuesItem => new() { - { OperationEnum.Equal, (int index, string? value) => new ValueEqaulSpec(index, value) }, + { OperationEnum.Equal, (int index, string? value) => new ValueEqualSpec(index, value) }, { OperationEnum.NotEqual, (int index, string? value) => new ValueNotEqualSpec(index, value) }, { OperationEnum.Greate, (int index, string? value) => new ValueGreateSpec(index, value) }, { OperationEnum.GreateOrEqual, (int index, string? value) => new ValueGreateOrEqualSpec(index, value) }, @@ -106,7 +106,7 @@ public static class FilterBuilder private static Dictionary>> DoubleSpecifications() where TEntity : IValuesItem => new() { - { OperationEnum.Equal, (int index, double? value) => new ValueEqaulSpec(index, value) }, + { OperationEnum.Equal, (int index, double? value) => new ValueEqualSpec(index, value) }, { OperationEnum.NotEqual, (int index, double? value) => new ValueNotEqualSpec(index, value) }, { OperationEnum.Greate, (int index, double? value) => new ValueGreateSpec(index, value) }, { OperationEnum.GreateOrEqual, (int index, double? value) => new ValueGreateOrEqualSpec(index, value) }, diff --git a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs index 23fd5e4..4153bd0 100644 --- a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs +++ b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs @@ -61,15 +61,15 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository resultQuery = resultQuery.Any() ? resultQuery.Union(query) : query; } var groupedQuery = resultQuery! - .GroupBy(e => e!.DiscriminatorId) + .GroupBy(e => e.DiscriminatorId) .Select(g => KeyValuePair.Create( g.Key, - g.OrderBy(i => i!.Timestamp).Skip(skip).Take(take)) + g.OrderBy(i => i.Timestamp).Skip(skip).Take(take)) ); var entities = await groupedQuery.ToArrayAsync(token); var result = entities.ToDictionary(k => k.Key, v => v.Value.Select(e => ( - e!.Timestamp, + e.Timestamp, e.Values ))); diff --git a/DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpec.cs b/DD.Persistence.Database/Specifications/ValuesItem/ValueEqualSpec.cs similarity index 77% rename from DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpec.cs rename to DD.Persistence.Database/Specifications/ValuesItem/ValueEqualSpec.cs index ec87fc1..2eed8c6 100644 --- a/DD.Persistence.Database/Specifications/ValuesItem/ValueEqaulSpec.cs +++ b/DD.Persistence.Database/Specifications/ValuesItem/ValueEqualSpec.cs @@ -7,15 +7,15 @@ namespace DD.Persistence.Database.Specifications.ValuesItem; /// Спецификация эквивалентности значений IValuesItem в соответствии с индексацией /// /// -public class ValueEqaulSpec : Specification +public class ValueEqualSpec : Specification where TEntity : IValuesItem { - public ValueEqaulSpec(int index, string? value) + public ValueEqualSpec(int index, string? value) { Query.Where(e => Convert.ToString(e.Values[index]) == value); } - public ValueEqaulSpec(int index, double? value) + public ValueEqualSpec(int index, double? value) { Query.Where(e => Convert.ToDouble(e.Values[index]) == value); } diff --git a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs index ab1ee20..4eaf415 100644 --- a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs +++ b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs @@ -56,7 +56,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest } catch (Exception ex) { - var expectedMessage = $" , "; + var expectedMessage = $"На сервере произошла ошибка, в результате которой он не может успешно обработать запрос"; //assert Assert.Equal(expectedMessage, ex.Message); @@ -78,7 +78,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest var timestampBegin = DateTimeOffset.UtcNow.AddDays(-1); var columnNames = new List() { "A", "C" }; var skip = 0; - var take = 6; // (\"A\">3) ( ) + var take = 6; // Ровно столько значений будет удовлетворять фильтру (\"A\">3) (для одного дискриминатора) var customFilter = "(\"A\">3)"; From 3cf7cbcc7cb67f401bc63a506811d3ac45d47460 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 12 Feb 2025 16:33:42 +0500 Subject: [PATCH 06/12] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Expressions/Terminal/Abstract/TerminalExpression.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs index 00ee20f..ff77715 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs @@ -62,6 +62,12 @@ abstract class TerminalExpression : IExpression private static object? ParseValue(string value) { + if (double.TryParse(value, out _)) + { + return double.Parse(value); + } + + // ToDo: избавиться var doubleValue= value.Replace('.', ','); if (double.TryParse(doubleValue, out _)) { From ca0b1f0031428ac76ed4755ca249ef301195f607 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Wed, 12 Feb 2025 16:43:34 +0500 Subject: [PATCH 07/12] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B0=20=D0=BD=D0=B0=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B5=D0=BA=D1=82=20=D1=81=20=D1=80=D0=B5=D0=BF=D0=BE?= =?UTF-8?q?=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D1=8F=D0=BC=D0=B8=20=D0=B8?= =?UTF-8?q?=D0=B7=20Dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.App/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/DD.Persistence.App/Dockerfile b/DD.Persistence.App/Dockerfile index fb8f35f..6f51afb 100644 --- a/DD.Persistence.App/Dockerfile +++ b/DD.Persistence.App/Dockerfile @@ -28,7 +28,6 @@ COPY ["DD.Persistence/DD.Persistence.csproj", "DD.Persistence/"] COPY ["DD.Persistence.Database/DD.Persistence.Database.csproj", "DD.Persistence.Database/"] COPY ["DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj", "DD.Persistence.Database.Postgres/"] COPY ["DD.Persistence.Models/DD.Persistence.Models.csproj", "DD.Persistence.Models/"] -COPY ["DD.Persistence.Repository/DD.Persistence.Repository.csproj", "DD.Persistence.Repository/"] RUN dotnet restore "./DD.Persistence.App/DD.Persistence.App.csproj" From 233850483cb9ef6aa95fa3183be2f3c1bb0ec813 Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 13 Feb 2025 13:22:28 +0500 Subject: [PATCH 08/12] =?UTF-8?q?UML-=D0=B4=D0=B8=D0=B0=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BC=D0=B0=20=D0=BF=D1=80=D0=BE=D1=86=D0=B5=D1=81=D1=81?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=BD=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.API/DD.Persistence.API.csproj | 4 + .../Docs/ChangeLog_actions.drawio.xml | 359 ++++++++++++++++++ 2 files changed, 363 insertions(+) create mode 100644 DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml diff --git a/DD.Persistence.API/DD.Persistence.API.csproj b/DD.Persistence.API/DD.Persistence.API.csproj index 38dd298..5038046 100644 --- a/DD.Persistence.API/DD.Persistence.API.csproj +++ b/DD.Persistence.API/DD.Persistence.API.csproj @@ -28,4 +28,8 @@ + + + + diff --git a/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml b/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml new file mode 100644 index 0000000..a911dd6 --- /dev/null +++ b/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml @@ -0,0 +1,359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b30d28dbeb4c9738ab67f21e07f71a48f8339bcb Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 13 Feb 2025 13:23:00 +0500 Subject: [PATCH 09/12] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=20=D1=84=D0=B0=D0=B9=D0=BB?= =?UTF-8?q?=D0=B5=20readme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.API/Readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DD.Persistence.API/Readme.md b/DD.Persistence.API/Readme.md index 43bbbf3..fb563a3 100644 --- a/DD.Persistence.API/Readme.md +++ b/DD.Persistence.API/Readme.md @@ -48,4 +48,7 @@ Password: 12345 } ``` +## Пакетное редактирование (на примере ChangeLog) +UWL-диаграмма процесса редактирования находится по ссылке: + From 36274b3a5e82bbf9b9053a7e4443374cdcf93956 Mon Sep 17 00:00:00 2001 From: "on.nemtina" Date: Thu, 13 Feb 2025 13:26:45 +0500 Subject: [PATCH 10/12] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20DD.Persistence.API/Readme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.API/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DD.Persistence.API/Readme.md b/DD.Persistence.API/Readme.md index fb563a3..0fbf84b 100644 --- a/DD.Persistence.API/Readme.md +++ b/DD.Persistence.API/Readme.md @@ -49,6 +49,6 @@ Password: 12345 ``` ## Пакетное редактирование (на примере ChangeLog) -UWL-диаграмма процесса редактирования находится по ссылке: +UWL-диаграмма процесса редактирования находится по [ссылке] https://git.ddrilling.ru/on.nemtina/persistence/src/branch/master/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml From 0d9c61c9058f65da09f2f1db8f982c0197be4705 Mon Sep 17 00:00:00 2001 From: "on.nemtina" Date: Thu, 13 Feb 2025 13:27:06 +0500 Subject: [PATCH 11/12] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20DD.Persistence.API/Readme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.API/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DD.Persistence.API/Readme.md b/DD.Persistence.API/Readme.md index 0fbf84b..0274ac1 100644 --- a/DD.Persistence.API/Readme.md +++ b/DD.Persistence.API/Readme.md @@ -49,6 +49,6 @@ Password: 12345 ``` ## Пакетное редактирование (на примере ChangeLog) -UWL-диаграмма процесса редактирования находится по [ссылке] https://git.ddrilling.ru/on.nemtina/persistence/src/branch/master/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml +UWL-диаграмма процесса редактирования находится по [ссылке](https://git.ddrilling.ru/on.nemtina/persistence/src/branch/master/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml) From 93472f79334b23170d51250314fc628741100a85 Mon Sep 17 00:00:00 2001 From: "on.nemtina" Date: Thu, 13 Feb 2025 13:27:58 +0500 Subject: [PATCH 12/12] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20DD.Persistence.API/Readme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.API/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DD.Persistence.API/Readme.md b/DD.Persistence.API/Readme.md index 0274ac1..85200fe 100644 --- a/DD.Persistence.API/Readme.md +++ b/DD.Persistence.API/Readme.md @@ -49,6 +49,6 @@ Password: 12345 ``` ## Пакетное редактирование (на примере ChangeLog) -UWL-диаграмма процесса редактирования находится по [ссылке](https://git.ddrilling.ru/on.nemtina/persistence/src/branch/master/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml) +UML-диаграмма процесса редактирования находится по [ссылке](https://git.ddrilling.ru/on.nemtina/persistence/src/branch/master/DD.Persistence.API/Docs/ChangeLog_actions.drawio.xml)