From 287d6e7111e4fbf3f13fc88f97ccbcf8e792aa26 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 08:46:08 +0500 Subject: [PATCH 01/13] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BF=D0=BE=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D0=B0=20=D0=B8=D0=B7=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.Test/TreeBuilderShould.cs | 107 ++++++++++++++++++ .../Models/Abstractions/INodeVisitor.cs | 22 ++++ .../Filter/Models/Abstractions/TNode.cs | 28 +++++ .../Models/Enumerations/OperationEnum.cs | 47 ++++++++ DD.Persistence/Filter/Models/TLeaf.cs | 33 ++++++ DD.Persistence/Filter/Models/TVertex.cs | 33 ++++++ .../TreeBuilder/Abstractions/ITreeBuilder.cs | 16 +++ .../Expressions/Abstractions/IExpression.cs | 27 +++++ .../Abstractions/NonTerminalExpression.cs | 83 ++++++++++++++ .../Expressions/NonTerminal/AndExpression.cs | 24 ++++ .../Expressions/NonTerminal/OrExpression.cs | 24 ++++ .../Terminal/Abstract/TerminalExpression.cs | 79 +++++++++++++ .../Expressions/Terminal/EqualExpression.cs | 24 ++++ .../Expressions/Terminal/LessExpression.cs | 24 ++++ .../Terminal/LessOrEqualExpression.cs | 24 ++++ .../Expressions/Terminal/MoreExpression.cs | 24 ++++ .../Terminal/MoreOrEqualExpression.cs | 24 ++++ .../Terminal/NotEqualExpression.cs | 24 ++++ .../Filter/TreeBuilder/InterpreterContext.cs | 31 +++++ .../Filter/TreeBuilder/TreeBuilder.cs | 52 +++++++++ DD.Persistence/Filter/Visitors/NodeVisitor.cs | 24 ++++ 21 files changed, 774 insertions(+) create mode 100644 DD.Persistence.Test/TreeBuilderShould.cs create mode 100644 DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs create mode 100644 DD.Persistence/Filter/Models/Abstractions/TNode.cs create mode 100644 DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs create mode 100644 DD.Persistence/Filter/Models/TLeaf.cs create mode 100644 DD.Persistence/Filter/Models/TVertex.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs create mode 100644 DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs create mode 100644 DD.Persistence/Filter/Visitors/NodeVisitor.cs diff --git a/DD.Persistence.Test/TreeBuilderShould.cs b/DD.Persistence.Test/TreeBuilderShould.cs new file mode 100644 index 0000000..f96f85b --- /dev/null +++ b/DD.Persistence.Test/TreeBuilderShould.cs @@ -0,0 +1,107 @@ +using DD.Persistence.Filter.Interpreter; +using DD.Persistence.Filter.Models; +using DD.Persistence.Filter.Models.Enumerations; +using Newtonsoft.Json; + +namespace DD.Persistence.Test; +public class TreeBuilderShould +{ + [Fact] + public void TestTreeBuilding() + { + //arrange + var treeString = "(\"A\"==1)||(\"B\"==2)&&(\"C\"==3)||((\"D\"==4)||(\"E\"==5))&&(\"F\"==6)"; + + //act + var root = treeString.BuildTree(); + + //assert + Assert.NotNull(root); + + var expectedRoot = JsonConvert.SerializeObject(new TVertex( + OperationEnum.And, + new TVertex( + OperationEnum.And, + new TVertex( + OperationEnum.Or, + new TLeaf(OperationEnum.Equal, "A", 1), + new TLeaf(OperationEnum.Equal, "B", 2) + ), + new TVertex( + OperationEnum.Or, + new TLeaf(OperationEnum.Equal, "C", 3), + new TVertex( + OperationEnum.Or, + new TLeaf(OperationEnum.Equal, "D", 4), + new TLeaf(OperationEnum.Equal, "E", 5) + ) + ) + ), + new TLeaf(OperationEnum.Equal, "F", 6) + )); + var actualRoot = JsonConvert.SerializeObject(root); + Assert.Equal(expectedRoot, actualRoot); + } + + [Fact] + public void TestTreeOperations() + { + //arrange + var treeString = "(\"A\"==1)||(\"B\"!=1)||(\"C\">1)||(\"D\">=1)||(\"E\"<1)||(\"F\"<=1)"; + + //act + var root = treeString.BuildTree(); + + //assert + Assert.NotNull(root); + + var expectedRoot = JsonConvert.SerializeObject(new TVertex( + OperationEnum.Or, + new TVertex( + OperationEnum.Or, + new TVertex( + OperationEnum.Or, + new TLeaf(OperationEnum.Equal, "A", 1), + new TLeaf(OperationEnum.NotEqual, "B", 1) + ), + new TVertex( + OperationEnum.Or, + new TLeaf(OperationEnum.Greate, "C", 1), + new TLeaf(OperationEnum.GreateOrEqual, "D", 1) + ) + ), + new TVertex( + OperationEnum.Or, + new TLeaf(OperationEnum.Less, "E", 1), + new TLeaf(OperationEnum.LessOrEqual, "F", 1) + ) + )); + var actualRoot = JsonConvert.SerializeObject(root); + Assert.Equal(expectedRoot, actualRoot); + } + + [Fact] + public void TestLeafValues() + { + //arrange + var treeString = "(\"A\"==1.2345)||(\"B\"==12345)||(\"C\"==\"12345\")"; + + //act + var root = treeString.BuildTree(); + + //assert + Assert.NotNull(root); + + var expectedRoot = JsonConvert.SerializeObject(new TVertex( + OperationEnum.Or, + new TVertex( + OperationEnum.Or, + new TLeaf(OperationEnum.Equal, "A", 1.2345), + new TLeaf(OperationEnum.Equal, "B", 12345) + ), + new TLeaf(OperationEnum.Equal, "C", "12345") + )); + var actualRoot = JsonConvert.SerializeObject(root); + Assert.Equal(expectedRoot, actualRoot); + } +} diff --git a/DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs b/DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs new file mode 100644 index 0000000..f039ee1 --- /dev/null +++ b/DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs @@ -0,0 +1,22 @@ +namespace DD.Persistence.Filter.Models.Abstractions; + +/// +/// Посетитель бинарного дерева +/// +/// +public interface INodeVisitor +{ + /// + /// Посетить узел + /// + /// + /// + TVisitResult Visit(TVertex vertex); + + /// + /// Посетить лист + /// + /// + /// + TVisitResult Visit(TLeaf leaf); +} diff --git a/DD.Persistence/Filter/Models/Abstractions/TNode.cs b/DD.Persistence/Filter/Models/Abstractions/TNode.cs new file mode 100644 index 0000000..226a3ef --- /dev/null +++ b/DD.Persistence/Filter/Models/Abstractions/TNode.cs @@ -0,0 +1,28 @@ +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.Models.Abstractions; + +/// +/// Абстрактная модель вершины +/// +public abstract class TNode +{ + /// + public TNode(OperationEnum operation) + { + Operation = operation; + } + + /// + /// Логическая операция + /// + public OperationEnum Operation { get; } + + /// + /// Принять посетителя + /// + /// + /// + /// + public abstract TVisitResult AcceptVisitor(INodeVisitor visitor); +} diff --git a/DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs b/DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs new file mode 100644 index 0000000..8f22b86 --- /dev/null +++ b/DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs @@ -0,0 +1,47 @@ +namespace DD.Persistence.Filter.Models.Enumerations; + +/// +/// Логические операции +/// +public enum OperationEnum +{ + /// + /// И + /// + And = 1, + + /// + /// ИЛИ + /// + Or = 2, + + /// + /// РАВНО + /// + Equal = 3, + + /// + /// НЕ РАВНО + /// + NotEqual = 4, + + /// + /// БОЛЬШЕ + /// + Greate = 5, + + /// + /// БОЛЬШЕ ЛИБО РАВНО + /// + GreateOrEqual = 6, + + /// + /// МЕНЬШЕ + /// + Less = 7, + + /// + /// МЕНЬШЕ ЛИБО РАВНО + /// + LessOrEqual = 8 +} diff --git a/DD.Persistence/Filter/Models/TLeaf.cs b/DD.Persistence/Filter/Models/TLeaf.cs new file mode 100644 index 0000000..d974ced --- /dev/null +++ b/DD.Persistence/Filter/Models/TLeaf.cs @@ -0,0 +1,33 @@ +using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.Models; + +/// +/// Модель листа +/// +public class TLeaf : TNode +{ + /// + /// Наименование поля + /// + public string PropName { get; } + + /// + /// Значение для фильтрации + /// + public object? Value { get; } + + /// + public TLeaf(OperationEnum operation, string fieldName, object? value) : base(operation) + { + PropName = fieldName; + Value = value; + } + + /// + public override TVisitResult AcceptVisitor(INodeVisitor visitor) + { + return visitor.Visit(this); + } +} diff --git a/DD.Persistence/Filter/Models/TVertex.cs b/DD.Persistence/Filter/Models/TVertex.cs new file mode 100644 index 0000000..3f6c200 --- /dev/null +++ b/DD.Persistence/Filter/Models/TVertex.cs @@ -0,0 +1,33 @@ +using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.Models; + +/// +/// Модель узла +/// +public class TVertex : TNode +{ + /// + /// Левый потомок + /// + public TNode Left { get; } + + /// + /// Правый потомок + /// + public TNode Rigth { get; } + + /// + public TVertex(OperationEnum operation, TNode left, TNode rigth) : base(operation) + { + Left = left; + Rigth = rigth; + } + + /// + public override TVisitResult AcceptVisitor(INodeVisitor visitor) + { + return visitor.Visit(this); + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs b/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs new file mode 100644 index 0000000..b512a53 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs @@ -0,0 +1,16 @@ +using DD.Persistence.Filter.Models.Abstractions; + +namespace DD.Persistence.Filter.Interpreter.Abstractions; + +/// +/// Интерпретатор для построения дерева +/// +public interface ITreeBuilder +{ + /// + /// Построить дерево + /// + /// Дерево в виде строки + /// Корень дерева в виде вершины + TNode? Build(string treeString); +} \ No newline at end of file diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs new file mode 100644 index 0000000..b28bde8 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs @@ -0,0 +1,27 @@ +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.Interpreter.Expressions.Abstract; + +/// +/// Интерфейс для выражений +/// +public interface IExpression +{ + /// + /// Получить логическую операцию + /// + /// + public OperationEnum GetOperation(); + + /// + /// Получить логическую операцию в виде строки (для регулярных выражений) + /// + /// + public string GetOperationString(); + + /// + /// Реализация правила + /// + /// + public void Interpret(InterpreterContext context); +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs new file mode 100644 index 0000000..137ec4b --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs @@ -0,0 +1,83 @@ +using DD.Persistence.Extensions; +using DD.Persistence.Filter.Interpreter.Expressions.Abstract; +using DD.Persistence.Filter.Models; +using DD.Persistence.Filter.Models.Enumerations; +using System.Text.RegularExpressions; + +namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base; + +/// +/// Абстрактный класс для нетерминальных выражений +/// +public abstract class NonTerminalExpression : IExpression +{ + /// + /// Реализация правила для нетерминальных выражений + /// + /// + public void Interpret(InterpreterContext context) + { + var operation = GetOperation(); + var operationString = GetOperationString(); + + var matches = GetMatches(context, operation, operationString); + while (matches.Any()) + { + matches.ForEach(m => + { + var matchString = m.ToString(); + + var separator = operationString.Replace("\\", string.Empty); + var pair = matchString + .Trim(['(', ')']) + .Split(separator) + .Select(e => int.Parse(e)); + + var leftNode = context.treeNodes + .FirstOrDefault(e => e.Key == pair.First()) + .Value; + var rigthNode = context.treeNodes + .FirstOrDefault(e => e.Key == pair.Last()) + .Value; + var node = new TVertex(operation, leftNode, rigthNode); + + var key = context.treeNodes.Count(); + context.treeNodes.Add(key, node); + + var keyString = key.ToString(); + context.treeString = context.treeString.Replace(matchString, keyString); + }); + + matches = GetMatches(context, operation, operationString); + } + + var isRoot = int.TryParse(context.treeString, out _); + if (isRoot) + { + context.treeString = string.Empty; + context.root = context.treeNodes.Last().Value; + } + } + + /// + public abstract OperationEnum GetOperation(); + + /// + public abstract string GetOperationString(); + + + /// + /// Получить из акткуального состояния строки все совпадения для текущего выражения + /// + private IEnumerable GetMatches(InterpreterContext context, OperationEnum operation, string operationString) + { + string pattern = context.treeString.Contains('(') && context.treeString.Contains(')') + ? $@"\(\d+{operationString}\d+\)" : $@"\d+{operationString}\d+"; + Regex regex = new Regex(pattern); + var matches = regex + .Matches(context.treeString) + .ToArray(); + + return matches; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs new file mode 100644 index 0000000..4a3d363 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal; + +/// +/// Выражение для "И" +/// +public class AndExpression : NonTerminalExpression +{ + private const string AndString = "&&"; + + /// + public override OperationEnum GetOperation() + { + return OperationEnum.And; + } + + /// + public override string GetOperationString() + { + return AndString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs new file mode 100644 index 0000000..e47b935 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal; + +/// +/// Выражение для "ИЛИ" +/// +public class OrExpression : NonTerminalExpression +{ + private const string OrString = @"\|\|"; + + /// + public override OperationEnum GetOperation() + { + return OperationEnum.Or; + } + + /// + public override string GetOperationString() + { + return OrString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs new file mode 100644 index 0000000..ada1f56 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs @@ -0,0 +1,79 @@ +using DD.Persistence.Extensions; +using DD.Persistence.Filter.Interpreter.Expressions.Abstract; +using DD.Persistence.Filter.Models; +using DD.Persistence.Filter.Models.Enumerations; +using System.Text.RegularExpressions; + +namespace DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; + +/// +/// Абстрактный класс для терминальных выражений +/// +public abstract class TerminalExpression : IExpression +{ + /// + /// Реализация правила для терминальных выражений + /// + /// + public void Interpret(InterpreterContext context) + { + var operation = GetOperation(); + var operationString = GetOperationString(); + + var matches = GetMatches(context, operation, operationString); + matches.ForEach(m => + { + var matchString = m.ToString(); + + var pair = matchString + .Trim(['(', ')']) + .Split(operationString); + var fieldName = pair + .First() + .Trim('\"'); + var value = ParseValue(pair.Last()); + var node = new TLeaf(operation, fieldName, value); + + var key = context.treeNodes.Count(); + context.treeNodes.Add(key, node); + + var keyString = key.ToString(); + context.treeString = context.treeString.Replace(matchString, keyString); + }); + } + + /// + public abstract OperationEnum GetOperation(); + + /// + public abstract string GetOperationString(); + + /// + /// Получить из акткуального состояния строки все совпадения для текущего выражения + /// + private IEnumerable GetMatches(InterpreterContext context, OperationEnum operation, string operationString) + { + string pattern = $@"\([^()]*{operationString}.*?\)"; + Regex regex = new Regex(pattern); + var matches = regex.Matches(context.treeString); + + return matches; + } + + private object? ParseValue(string value) + { + value = value.Replace('.', ','); + if (value.Contains(',') && double.TryParse(value, out _)) + { + return double.Parse(value); + } + + if (int.TryParse(value, out _)) + { + return int.Parse(value); + } + + value = value.Trim('\"'); + return value; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs new file mode 100644 index 0000000..4c78e36 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; + +/// +/// Выражение для "РАВНО" +/// +public class EqualExpression : TerminalExpression +{ + private const string EqualString = "=="; + + /// + public override OperationEnum GetOperation() + { + return OperationEnum.Equal; + } + + /// + public override string GetOperationString() + { + return EqualString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs new file mode 100644 index 0000000..a7e6902 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; + +/// +/// Выражение для "МЕНЬШЕ" +/// +public class LessExpression : TerminalExpression +{ + private const string EqualString = "<"; + + /// + public override OperationEnum GetOperation() + { + return OperationEnum.Less; + } + + /// + public override string GetOperationString() + { + return EqualString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs new file mode 100644 index 0000000..9a5c6be --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; + +/// +/// Выражение для "МЕНЬШЕ ЛИБО РАВНО" +/// +public class LessOrEqualExpression : TerminalExpression +{ + private const string EqualString = "<="; + + /// + public override OperationEnum GetOperation() + { + return OperationEnum.LessOrEqual; + } + + /// + public override string GetOperationString() + { + return EqualString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs new file mode 100644 index 0000000..0d6c8b0 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; + +/// +/// Выражение для "БОЛЬШЕ" +/// +public class MoreExpression : TerminalExpression +{ + private const string EqualString = ">"; + + /// + public override OperationEnum GetOperation() + { + return OperationEnum.Greate; + } + + /// + public override string GetOperationString() + { + return EqualString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs new file mode 100644 index 0000000..1dd2db4 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; + +/// +/// Выражение для "БОЛЬШЕ ЛИБО РАВНО" +/// +public class MoreOrEqualExpression : TerminalExpression +{ + private const string EqualString = ">="; + + /// + public override OperationEnum GetOperation() + { + return OperationEnum.GreateOrEqual; + } + + /// + public override string GetOperationString() + { + return EqualString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs new file mode 100644 index 0000000..b51817a --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; +using DD.Persistence.Filter.Models.Enumerations; + +namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; + +/// +/// Выражение для "НЕРАВНО" +/// +public class NotEqualExpression : TerminalExpression +{ + private const string NotEqulString = "!="; + + /// + public override OperationEnum GetOperation() + { + return OperationEnum.NotEqual; + } + + /// + public override string GetOperationString() + { + return NotEqulString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs new file mode 100644 index 0000000..f07cd10 --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs @@ -0,0 +1,31 @@ +using DD.Persistence.Filter.Models.Abstractions; + +namespace DD.Persistence.Filter.Interpreter; + +/// +/// Контекст интерпретатора +/// +public class InterpreterContext +{ + /// + /// Корень дерева (результат интерпретации) + /// + public TNode? root { get; set; } + + /// + /// Дерево в виде строки (входной параметр) + /// + public string treeString { get; set; } + + /// + /// Проиндексированные вершины дерева + /// + //public Dictionary treeNodes { get; set; } = []; + public Dictionary treeNodes { get; set; } = []; + + /// + public InterpreterContext(string theeString) + { + this.treeString = theeString; + } +} diff --git a/DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs b/DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs new file mode 100644 index 0000000..224c74c --- /dev/null +++ b/DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs @@ -0,0 +1,52 @@ +using DD.Persistence.Filter.Interpreter.Expressions.Abstract; +using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal; +using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; + +namespace DD.Persistence.Filter.Interpreter; + +/// +/// Строитель бинарных деревьев +/// +public static class TreeBuilder +{ + + /// + /// Построить бинарное дерево логических операций сравнения из строки + /// + /// + /// + public static TNode? BuildTree(this string treeString) + { + InterpreterContext context = new InterpreterContext(treeString); + + // Порядок важен + List terminalExpressions = new List + { + new EqualExpression(), + new NotEqualExpression(), + new MoreOrEqualExpression(), + new LessOrEqualExpression(), + new MoreExpression(), + new LessExpression() + }; + terminalExpressions.ForEach(e => { + e.Interpret(context); + }); + + // Порядок важен + List nonTerminalExpressions = new List + { + new OrExpression(), + new AndExpression() + }; + while (!string.IsNullOrEmpty(context.treeString)) + { + nonTerminalExpressions.ForEach(e => { + e.Interpret(context); + }); + } + + return context.root; + } +} diff --git a/DD.Persistence/Filter/Visitors/NodeVisitor.cs b/DD.Persistence/Filter/Visitors/NodeVisitor.cs new file mode 100644 index 0000000..07c7792 --- /dev/null +++ b/DD.Persistence/Filter/Visitors/NodeVisitor.cs @@ -0,0 +1,24 @@ +using DD.Persistence.Filter.Models; +using DD.Persistence.Filter.Models.Abstractions; + +namespace DD.Persistence.Filter.Visitors; + +/// +public class NodeVisitor : INodeVisitor +{ + private readonly Func _ifVertex; + private readonly Func _ifLeaf; + + /// + public NodeVisitor(Func ifVertex, Func ifLeaf) + { + _ifVertex = ifVertex; + _ifLeaf = ifLeaf; + } + + /// + public TVisitResult Visit(TVertex vertex) => _ifVertex(vertex); + + /// + public TVisitResult Visit(TLeaf leaf) => _ifLeaf(leaf); +} From cb0508afe9ea713be7d7a9abddafe026d50d1591 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 08:48:20 +0500 Subject: [PATCH 02/13] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D0=BA=D0=BE=D0=BC=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs index f07cd10..72e0384 100644 --- a/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs +++ b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs @@ -20,7 +20,6 @@ public class InterpreterContext /// /// Проиндексированные вершины дерева /// - //public Dictionary treeNodes { get; set; } = []; public Dictionary treeNodes { get; set; } = []; /// From f955aab2181f20a671de1b7a3435e4c0df2d29e7 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 09:16:28 +0500 Subject: [PATCH 03/13] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20=D1=81=D0=BE=D0=B4=D0=B5=D1=80=D0=B6=D0=B8?= =?UTF-8?q?=D0=BC=D0=BE=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0?= =?UTF-8?q?=20DD.Persistence.Repository=20=D0=B2=20DD.Persistence.Database?= =?UTF-8?q?.Postgres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.API/DD.Persistence.API.csproj | 1 - DD.Persistence.API/Startup.cs | 1 - .../DD.Persistence.Database.Postgres.csproj | 2 + .../DependencyInjection.cs | 42 ++++++++++++++++- .../Extensions/EFExtensionsSortBy.cs | 2 +- .../Helpers}/CyclicArray.cs | 2 +- .../Helpers}/QueryBuilders.cs | 13 +++--- .../Repositories/ChangeLogRepository.cs | 3 +- .../Repositories/DataSchemeRepository.cs | 2 +- .../DataSourceSystemRepository.cs | 2 +- .../Repositories/ParameterRepository.cs | 2 +- .../Repositories/SetpointRepository.cs | 2 +- .../Repositories/TechMessagesRepository.cs | 2 +- .../TimestampedValuesRepository.cs | 14 +++++- .../DataSchemeCachedRepository.cs | 4 +- .../DataSourceSystemCachedRepository.cs | 4 +- .../TimestampedValuesCachedRepository.cs | 2 +- .../DD.Persistence.Repository.Test.csproj | 1 - .../SetpointRepositoryShould.cs | 7 +-- .../DD.Persistence.Repository.csproj | 19 -------- .../DependencyInjection.cs | 45 ------------------- DD.Persistence.sln | 6 --- 22 files changed, 76 insertions(+), 102 deletions(-) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/Extensions/EFExtensionsSortBy.cs (99%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres/Helpers}/CyclicArray.cs (99%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres/Helpers}/QueryBuilders.cs (90%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/Repositories/ChangeLogRepository.cs (98%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/Repositories/DataSchemeRepository.cs (94%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/Repositories/DataSourceSystemRepository.cs (94%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/Repositories/ParameterRepository.cs (98%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/Repositories/SetpointRepository.cs (98%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/Repositories/TechMessagesRepository.cs (98%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/Repositories/TimestampedValuesRepository.cs (91%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/RepositoriesCached/DataSchemeCachedRepository.cs (88%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/RepositoriesCached/DataSourceSystemCachedRepository.cs (91%) rename {DD.Persistence.Repository => DD.Persistence.Database.Postgres}/RepositoriesCached/TimestampedValuesCachedRepository.cs (98%) delete mode 100644 DD.Persistence.Repository/DD.Persistence.Repository.csproj delete mode 100644 DD.Persistence.Repository/DependencyInjection.cs diff --git a/DD.Persistence.API/DD.Persistence.API.csproj b/DD.Persistence.API/DD.Persistence.API.csproj index 5ed1097..38dd298 100644 --- a/DD.Persistence.API/DD.Persistence.API.csproj +++ b/DD.Persistence.API/DD.Persistence.API.csproj @@ -25,7 +25,6 @@ - diff --git a/DD.Persistence.API/Startup.cs b/DD.Persistence.API/Startup.cs index 1a880c0..bc78548 100644 --- a/DD.Persistence.API/Startup.cs +++ b/DD.Persistence.API/Startup.cs @@ -1,6 +1,5 @@ using DD.Persistence.Database.Model; using DD.Persistence.Database.Postgres.Extensions; -using DD.Persistence.Repository; namespace DD.Persistence.API; diff --git a/DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj b/DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj index bf406a6..80b6736 100644 --- a/DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj +++ b/DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj @@ -7,11 +7,13 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/DD.Persistence.Database.Postgres/DependencyInjection.cs b/DD.Persistence.Database.Postgres/DependencyInjection.cs index f0c8ff1..0509061 100644 --- a/DD.Persistence.Database.Postgres/DependencyInjection.cs +++ b/DD.Persistence.Database.Postgres/DependencyInjection.cs @@ -1,6 +1,13 @@ -using Microsoft.EntityFrameworkCore; +using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Postgres.Repositories; +using DD.Persistence.Database.Postgres.RepositoriesCached; +using DD.Persistence.Models; +using DD.Persistence.Repositories; +using Mapster; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using System.Reflection; namespace DD.Persistence.Database.Model; @@ -17,4 +24,37 @@ public static class DependencyInjection return services; } + + public static void MapsterSetup() + { + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .Ignore(dest => dest.System, dest => dest.SystemId); + + TypeAdapterConfig.NewConfig() + .Map(dest => dest.Value, src => new ChangeLogValuesDto() + { + Value = src.Value, + Id = src.Id + }); + } + + public static IServiceCollection AddInfrastructure(this IServiceCollection services) + { + var typeAdapterConfig = TypeAdapterConfig.GlobalSettings; + typeAdapterConfig.RuleMap.Clear(); + typeAdapterConfig.Scan(Assembly.GetExecutingAssembly()); + + MapsterSetup(); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + return services; + } } diff --git a/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs b/DD.Persistence.Database.Postgres/Extensions/EFExtensionsSortBy.cs similarity index 99% rename from DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs rename to DD.Persistence.Database.Postgres/Extensions/EFExtensionsSortBy.cs index bed529e..3af7ae0 100644 --- a/DD.Persistence.Repository/Extensions/EFExtensionsSortBy.cs +++ b/DD.Persistence.Database.Postgres/Extensions/EFExtensionsSortBy.cs @@ -2,7 +2,7 @@ using System.Collections.Concurrent; using System.Linq.Expressions; using System.Reflection; -namespace DD.Persistence.Repository.Extensions; +namespace DD.Persistence.Database.Postgres.Extensions; public static class EFExtensionsSortBy { diff --git a/DD.Persistence.Repository/CyclicArray.cs b/DD.Persistence.Database.Postgres/Helpers/CyclicArray.cs similarity index 99% rename from DD.Persistence.Repository/CyclicArray.cs rename to DD.Persistence.Database.Postgres/Helpers/CyclicArray.cs index 7a7ea1d..fcb5793 100644 --- a/DD.Persistence.Repository/CyclicArray.cs +++ b/DD.Persistence.Database.Postgres/Helpers/CyclicArray.cs @@ -1,6 +1,6 @@ using System.Collections; -namespace DD.Persistence.Repository; +namespace DD.Persistence.Database.Postgres.Helpers; /// /// Цикличный массив /// diff --git a/DD.Persistence.Repository/QueryBuilders.cs b/DD.Persistence.Database.Postgres/Helpers/QueryBuilders.cs similarity index 90% rename from DD.Persistence.Repository/QueryBuilders.cs rename to DD.Persistence.Database.Postgres/Helpers/QueryBuilders.cs index 52b6429..8529230 100644 --- a/DD.Persistence.Repository/QueryBuilders.cs +++ b/DD.Persistence.Database.Postgres/Helpers/QueryBuilders.cs @@ -1,11 +1,10 @@ -using Microsoft.EntityFrameworkCore; -using DD.Persistence.Models.Requests; -using DD.Persistence.Models.Common; -using DD.Persistence.ModelsAbstractions; -using DD.Persistence.Database.EntityAbstractions; +using DD.Persistence.Database.EntityAbstractions; using DD.Persistence.Extensions; +using DD.Persistence.Models.Common; +using DD.Persistence.Models.Requests; +using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository; +namespace DD.Persistence.Database.Postgres.Helpers; /// /// класс с набором методов, необходимых для фильтрации записей @@ -55,4 +54,4 @@ public static class QueryBuilders return result; } -} +} \ No newline at end of file diff --git a/DD.Persistence.Repository/Repositories/ChangeLogRepository.cs b/DD.Persistence.Database.Postgres/Repositories/ChangeLogRepository.cs similarity index 98% rename from DD.Persistence.Repository/Repositories/ChangeLogRepository.cs rename to DD.Persistence.Database.Postgres/Repositories/ChangeLogRepository.cs index 2af06ce..c2502ef 100644 --- a/DD.Persistence.Repository/Repositories/ChangeLogRepository.cs +++ b/DD.Persistence.Database.Postgres/Repositories/ChangeLogRepository.cs @@ -1,4 +1,5 @@ using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Postgres.Helpers; using DD.Persistence.Models; using DD.Persistence.Models.Common; using DD.Persistence.Models.Requests; @@ -7,7 +8,7 @@ using Mapster; using Microsoft.EntityFrameworkCore; using UuidExtensions; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Postgres.Repositories; public class ChangeLogRepository : IChangeLogRepository { private readonly DbContext db; diff --git a/DD.Persistence.Repository/Repositories/DataSchemeRepository.cs b/DD.Persistence.Database.Postgres/Repositories/DataSchemeRepository.cs similarity index 94% rename from DD.Persistence.Repository/Repositories/DataSchemeRepository.cs rename to DD.Persistence.Database.Postgres/Repositories/DataSchemeRepository.cs index c30c8da..ba5ccd7 100644 --- a/DD.Persistence.Repository/Repositories/DataSchemeRepository.cs +++ b/DD.Persistence.Database.Postgres/Repositories/DataSchemeRepository.cs @@ -4,7 +4,7 @@ using DD.Persistence.Repositories; using Mapster; using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Postgres.Repositories; public class DataSchemeRepository : IDataSchemeRepository { protected DbContext db; diff --git a/DD.Persistence.Repository/Repositories/DataSourceSystemRepository.cs b/DD.Persistence.Database.Postgres/Repositories/DataSourceSystemRepository.cs similarity index 94% rename from DD.Persistence.Repository/Repositories/DataSourceSystemRepository.cs rename to DD.Persistence.Database.Postgres/Repositories/DataSourceSystemRepository.cs index d8b6c0a..d9e7fa7 100644 --- a/DD.Persistence.Repository/Repositories/DataSourceSystemRepository.cs +++ b/DD.Persistence.Database.Postgres/Repositories/DataSourceSystemRepository.cs @@ -4,7 +4,7 @@ using DD.Persistence.Repositories; using Mapster; using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Postgres.Repositories; public class DataSourceSystemRepository : IDataSourceSystemRepository { protected DbContext db; diff --git a/DD.Persistence.Repository/Repositories/ParameterRepository.cs b/DD.Persistence.Database.Postgres/Repositories/ParameterRepository.cs similarity index 98% rename from DD.Persistence.Repository/Repositories/ParameterRepository.cs rename to DD.Persistence.Database.Postgres/Repositories/ParameterRepository.cs index d241de7..c489cd7 100644 --- a/DD.Persistence.Repository/Repositories/ParameterRepository.cs +++ b/DD.Persistence.Database.Postgres/Repositories/ParameterRepository.cs @@ -5,7 +5,7 @@ using DD.Persistence.Models; using DD.Persistence.Repositories; using DD.Persistence.Models.Common; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Postgres.Repositories; public class ParameterRepository : IParameterRepository { private DbContext db; diff --git a/DD.Persistence.Repository/Repositories/SetpointRepository.cs b/DD.Persistence.Database.Postgres/Repositories/SetpointRepository.cs similarity index 98% rename from DD.Persistence.Repository/Repositories/SetpointRepository.cs rename to DD.Persistence.Database.Postgres/Repositories/SetpointRepository.cs index 97c6098..3cfd9b1 100644 --- a/DD.Persistence.Repository/Repositories/SetpointRepository.cs +++ b/DD.Persistence.Database.Postgres/Repositories/SetpointRepository.cs @@ -6,7 +6,7 @@ using Mapster; using Microsoft.EntityFrameworkCore; using System.Text.Json; -namespace DD.Persistence.Repository.Repositories +namespace DD.Persistence.Database.Postgres.Repositories { public class SetpointRepository : ISetpointRepository { diff --git a/DD.Persistence.Repository/Repositories/TechMessagesRepository.cs b/DD.Persistence.Database.Postgres/Repositories/TechMessagesRepository.cs similarity index 98% rename from DD.Persistence.Repository/Repositories/TechMessagesRepository.cs rename to DD.Persistence.Database.Postgres/Repositories/TechMessagesRepository.cs index 1a84f25..15d8fe8 100644 --- a/DD.Persistence.Repository/Repositories/TechMessagesRepository.cs +++ b/DD.Persistence.Database.Postgres/Repositories/TechMessagesRepository.cs @@ -7,7 +7,7 @@ using DD.Persistence.Repositories; using Mapster; using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository.Repositories +namespace DD.Persistence.Database.Postgres.Repositories { public class TechMessagesRepository : ITechMessagesRepository { diff --git a/DD.Persistence.Repository/Repositories/TimestampedValuesRepository.cs b/DD.Persistence.Database.Postgres/Repositories/TimestampedValuesRepository.cs similarity index 91% rename from DD.Persistence.Repository/Repositories/TimestampedValuesRepository.cs rename to DD.Persistence.Database.Postgres/Repositories/TimestampedValuesRepository.cs index 2005a5a..149e411 100644 --- a/DD.Persistence.Repository/Repositories/TimestampedValuesRepository.cs +++ b/DD.Persistence.Database.Postgres/Repositories/TimestampedValuesRepository.cs @@ -4,7 +4,7 @@ using DD.Persistence.Models.Common; using DD.Persistence.Repositories; using Microsoft.EntityFrameworkCore; -namespace DD.Persistence.Repository.Repositories; +namespace DD.Persistence.Database.Postgres.Repositories; public class TimestampedValuesRepository : ITimestampedValuesRepository { private readonly DbContext db; @@ -14,7 +14,8 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository this.db = db; } - protected virtual IQueryable GetQueryReadOnly() => this.db.Set(); + protected virtual IQueryable GetQueryReadOnly() => this.db.Set() + .Include(e => e.DataScheme); public async virtual Task AddRange(Guid discriminatorId, IEnumerable dtos, CancellationToken token) { @@ -54,6 +55,15 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository .Select(g => KeyValuePair.Create(g.Key, g.OrderBy(i => i.Timestamp).Skip(skip).Take(take))); var entities = await groupQuery.ToArrayAsync(token); + //var root = new TVertex( + // OperationEnum.And, + // new TLeaf(OperationEnum.Equal, "A", 1), + // new TLeaf(OperationEnum.Equal, "B", 1) + //); + //var dataScheme = entities.First().Value.First().DataScheme; + //var specification = dataScheme.BuildFilter(root); + //var que = ApplySpecification(specification); + var result = entities.ToDictionary(k => k.Key, v => v.Value.Select(e => ( e.Timestamp, e.Values diff --git a/DD.Persistence.Repository/RepositoriesCached/DataSchemeCachedRepository.cs b/DD.Persistence.Database.Postgres/RepositoriesCached/DataSchemeCachedRepository.cs similarity index 88% rename from DD.Persistence.Repository/RepositoriesCached/DataSchemeCachedRepository.cs rename to DD.Persistence.Database.Postgres/RepositoriesCached/DataSchemeCachedRepository.cs index ea22196..f4cec62 100644 --- a/DD.Persistence.Repository/RepositoriesCached/DataSchemeCachedRepository.cs +++ b/DD.Persistence.Database.Postgres/RepositoriesCached/DataSchemeCachedRepository.cs @@ -1,9 +1,9 @@ using DD.Persistence.Models; -using DD.Persistence.Repository.Repositories; +using DD.Persistence.Database.Postgres.Repositories; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; -namespace DD.Persistence.Repository.RepositoriesCached; +namespace DD.Persistence.Database.Postgres.RepositoriesCached; public class DataSchemeCachedRepository : DataSchemeRepository { private readonly IMemoryCache memoryCache; diff --git a/DD.Persistence.Repository/RepositoriesCached/DataSourceSystemCachedRepository.cs b/DD.Persistence.Database.Postgres/RepositoriesCached/DataSourceSystemCachedRepository.cs similarity index 91% rename from DD.Persistence.Repository/RepositoriesCached/DataSourceSystemCachedRepository.cs rename to DD.Persistence.Database.Postgres/RepositoriesCached/DataSourceSystemCachedRepository.cs index 87e487e..919c3ba 100644 --- a/DD.Persistence.Repository/RepositoriesCached/DataSourceSystemCachedRepository.cs +++ b/DD.Persistence.Database.Postgres/RepositoriesCached/DataSourceSystemCachedRepository.cs @@ -1,10 +1,10 @@ using DD.Persistence.Database.Entity; using DD.Persistence.Models; -using DD.Persistence.Repository.Repositories; +using DD.Persistence.Database.Postgres.Repositories; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; -namespace DD.Persistence.Repository.RepositoriesCached; +namespace DD.Persistence.Database.Postgres.RepositoriesCached; public class DataSourceSystemCachedRepository : DataSourceSystemRepository { private static readonly string SystemCacheKey = $"{typeof(DataSourceSystem).FullName}CacheKey"; diff --git a/DD.Persistence.Repository/RepositoriesCached/TimestampedValuesCachedRepository.cs b/DD.Persistence.Database.Postgres/RepositoriesCached/TimestampedValuesCachedRepository.cs similarity index 98% rename from DD.Persistence.Repository/RepositoriesCached/TimestampedValuesCachedRepository.cs rename to DD.Persistence.Database.Postgres/RepositoriesCached/TimestampedValuesCachedRepository.cs index f81f7a0..2073126 100644 --- a/DD.Persistence.Repository/RepositoriesCached/TimestampedValuesCachedRepository.cs +++ b/DD.Persistence.Database.Postgres/RepositoriesCached/TimestampedValuesCachedRepository.cs @@ -3,7 +3,7 @@ //using DD.Persistence.Repositories; //using Microsoft.EntityFrameworkCore; -//namespace DD.Persistence.Repository.Repositories; +//namespace DD.Persistence.Database.Postgres.Repositories; //public class TimestampedValuesCachedRepository : TimestampedValuesRepository //{ diff --git a/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj b/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj index 4f29d86..63b4134 100644 --- a/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj +++ b/DD.Persistence.Repository.Test/DD.Persistence.Repository.Test.csproj @@ -20,7 +20,6 @@ - diff --git a/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs b/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs index 6b05ff3..44c518a 100644 --- a/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs +++ b/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs @@ -1,12 +1,7 @@ using DD.Persistence.Database.Model; -using DD.Persistence.Repository.Repositories; +using DD.Persistence.Database.Postgres.Repositories; using Shouldly; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Text.Json; -using System.Threading.Tasks; namespace DD.Persistence.Repository.Test; public class SetpointRepositoryShould : IClassFixture diff --git a/DD.Persistence.Repository/DD.Persistence.Repository.csproj b/DD.Persistence.Repository/DD.Persistence.Repository.csproj deleted file mode 100644 index 75803db..0000000 --- a/DD.Persistence.Repository/DD.Persistence.Repository.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - net9.0 - enable - enable - - - - - - - - - - - - - diff --git a/DD.Persistence.Repository/DependencyInjection.cs b/DD.Persistence.Repository/DependencyInjection.cs deleted file mode 100644 index a6ae2af..0000000 --- a/DD.Persistence.Repository/DependencyInjection.cs +++ /dev/null @@ -1,45 +0,0 @@ -using DD.Persistence.Database.Entity; -using DD.Persistence.Models; -using DD.Persistence.Repositories; -using DD.Persistence.Repository.Repositories; -using DD.Persistence.Repository.RepositoriesCached; -using Mapster; -using Microsoft.Extensions.DependencyInjection; -using System.Reflection; - -namespace DD.Persistence.Repository; -public static class DependencyInjection -{ - public static void MapsterSetup() - { - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .Ignore(dest => dest.System, dest => dest.SystemId); - - TypeAdapterConfig.NewConfig() - .Map(dest => dest.Value, src => new ChangeLogValuesDto() - { - Value = src.Value, - Id = src.Id - }); - } - - public static IServiceCollection AddInfrastructure(this IServiceCollection services) - { - var typeAdapterConfig = TypeAdapterConfig.GlobalSettings; - typeAdapterConfig.RuleMap.Clear(); - typeAdapterConfig.Scan(Assembly.GetExecutingAssembly()); - - MapsterSetup(); - - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - return services; - } -} diff --git a/DD.Persistence.sln b/DD.Persistence.sln index ca91e47..e42f411 100644 --- a/DD.Persistence.sln +++ b/DD.Persistence.sln @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence", "DD.Persis EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.API", "DD.Persistence.API\DD.Persistence.API.csproj", "{8650A227-929E-45F0-AEF7-2C91F45FE884}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.Repository", "DD.Persistence.Repository\DD.Persistence.Repository.csproj", "{493D6D92-231B-4CB6-831B-BE13884B0DE4}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.Database", "DD.Persistence.Database\DD.Persistence.Database.csproj", "{F77475D1-D074-407A-9D69-2FADDDAE2056}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DD.Persistence.IntegrationTests", "DD.Persistence.IntegrationTests\DD.Persistence.IntegrationTests.csproj", "{10752C25-3773-4081-A1F2-215A1D950126}" @@ -51,10 +49,6 @@ Global {8650A227-929E-45F0-AEF7-2C91F45FE884}.Debug|Any CPU.Build.0 = Debug|Any CPU {8650A227-929E-45F0-AEF7-2C91F45FE884}.Release|Any CPU.ActiveCfg = Release|Any CPU {8650A227-929E-45F0-AEF7-2C91F45FE884}.Release|Any CPU.Build.0 = Release|Any CPU - {493D6D92-231B-4CB6-831B-BE13884B0DE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {493D6D92-231B-4CB6-831B-BE13884B0DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {493D6D92-231B-4CB6-831B-BE13884B0DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {493D6D92-231B-4CB6-831B-BE13884B0DE4}.Release|Any CPU.Build.0 = Release|Any CPU {F77475D1-D074-407A-9D69-2FADDDAE2056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F77475D1-D074-407A-9D69-2FADDDAE2056}.Debug|Any CPU.Build.0 = Debug|Any CPU {F77475D1-D074-407A-9D69-2FADDDAE2056}.Release|Any CPU.ActiveCfg = Release|Any CPU From 1d0921c3e86b0af37907fb659568252698fd180b Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 09:56:49 +0500 Subject: [PATCH 04/13] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D1=82=D1=8C=20=D1=81=D1=85=D0=B5=D0=BC=D1=83=20?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=BF=D0=BE=20=D1=87?= =?UTF-8?q?=D0=B0=D1=81=D1=82=D0=B8=20=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=82=D0=B8=D0=BF=D0=BE=D0=B2=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9=20=D0=B2=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2?= =?UTF-8?q?=D0=B5=D1=82=D1=81=D1=82=D0=B2=D0=B8=D0=B8=20=D1=81=20=D0=B8?= =?UTF-8?q?=D0=BD=D0=B4=D0=B5=D0=BA=D1=81=D0=B0=D1=86=D0=B8=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ner.cs => 20250204044050_Init.Designer.cs} | 7 ++- ...3061429_Init.cs => 20250204044050_Init.cs} | 3 +- ...PersistencePostgresContextModelSnapshot.cs | 5 ++ DD.Persistence.Database/Entity/DataScheme.cs | 6 +- .../TimestampedValuesControllerTest.cs | 3 +- DD.Persistence.Models/DataSchemeDto.cs | 5 ++ .../Enumerations/PropTypeEnum.cs | 14 +++++ .../Services/TimestampedValuesService.cs | 62 ++++++++++++++----- 8 files changed, 84 insertions(+), 21 deletions(-) rename DD.Persistence.Database.Postgres/Migrations/{20250203061429_Init.Designer.cs => 20250204044050_Init.Designer.cs} (97%) rename DD.Persistence.Database.Postgres/Migrations/{20250203061429_Init.cs => 20250204044050_Init.cs} (97%) create mode 100644 DD.Persistence.Models/Enumerations/PropTypeEnum.cs diff --git a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs b/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs similarity index 97% rename from DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs rename to DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs index bdeaf87..60e6e92 100644 --- a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.Designer.cs +++ b/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs @@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace DD.Persistence.Database.Postgres.Migrations { [DbContext(typeof(PersistencePostgresContext))] - [Migration("20250203061429_Init")] + [Migration("20250204044050_Init")] partial class Init { /// @@ -79,6 +79,11 @@ namespace DD.Persistence.Database.Postgres.Migrations .HasColumnType("jsonb") .HasComment("Наименования полей в порядке индексации"); + b.PrimitiveCollection("PropTypes") + .IsRequired() + .HasColumnType("integer[]") + .HasComment("Типы полей в порядке индексации"); + b.HasKey("DiscriminatorId"); b.ToTable("data_scheme"); diff --git a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs b/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs similarity index 97% rename from DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs rename to DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs index df996bc..24a310d 100644 --- a/DD.Persistence.Database.Postgres/Migrations/20250203061429_Init.cs +++ b/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs @@ -35,7 +35,8 @@ namespace DD.Persistence.Database.Postgres.Migrations columns: table => new { DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"), - PropNames = table.Column(type: "jsonb", nullable: false, comment: "Наименования полей в порядке индексации") + PropNames = table.Column(type: "jsonb", nullable: false, comment: "Наименования полей в порядке индексации"), + PropTypes = table.Column(type: "integer[]", nullable: false, comment: "Типы полей в порядке индексации") }, constraints: table => { diff --git a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs index 5c5ad2e..ca319a5 100644 --- a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs +++ b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs @@ -76,6 +76,11 @@ namespace DD.Persistence.Database.Postgres.Migrations .HasColumnType("jsonb") .HasComment("Наименования полей в порядке индексации"); + b.PrimitiveCollection("PropTypes") + .IsRequired() + .HasColumnType("integer[]") + .HasComment("Типы полей в порядке индексации"); + b.HasKey("DiscriminatorId"); b.ToTable("data_scheme"); diff --git a/DD.Persistence.Database/Entity/DataScheme.cs b/DD.Persistence.Database/Entity/DataScheme.cs index 75794c0..a231580 100644 --- a/DD.Persistence.Database/Entity/DataScheme.cs +++ b/DD.Persistence.Database/Entity/DataScheme.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; +using DD.Persistence.Models; +using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -12,4 +13,7 @@ public class DataScheme [Comment("Наименования полей в порядке индексации"), Column(TypeName = "jsonb")] public string[] PropNames { get; set; } = []; + + [Comment("Типы полей в порядке индексации")] + public PropTypeEnum[] PropTypes { get; set; } = []; } diff --git a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs index c6642a5..526b372 100644 --- a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs +++ b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs @@ -3,7 +3,6 @@ using DD.Persistence.Client.Clients; using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client.Clients.Interfaces.Refit; using DD.Persistence.Database.Entity; -using DD.Persistence.Extensions; using DD.Persistence.Models; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; @@ -267,7 +266,7 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest var count = 2048; var timestampBegin = DateTimeOffset.UtcNow; var dtos = await AddRange(discriminatorId, count); - + //act var response = await timestampedValuesClient.GetResampledData(discriminatorId, timestampBegin, count); diff --git a/DD.Persistence.Models/DataSchemeDto.cs b/DD.Persistence.Models/DataSchemeDto.cs index d1efdd5..7f238aa 100644 --- a/DD.Persistence.Models/DataSchemeDto.cs +++ b/DD.Persistence.Models/DataSchemeDto.cs @@ -14,4 +14,9 @@ public class DataSchemeDto /// Наименования полей /// public string[] PropNames { get; set; } = []; + + /// + /// Типы полей + /// + public PropTypeEnum[] PropTypes { get; set; } = []; } diff --git a/DD.Persistence.Models/Enumerations/PropTypeEnum.cs b/DD.Persistence.Models/Enumerations/PropTypeEnum.cs new file mode 100644 index 0000000..5379929 --- /dev/null +++ b/DD.Persistence.Models/Enumerations/PropTypeEnum.cs @@ -0,0 +1,14 @@ +namespace DD.Persistence.Models; + +/// +/// Типы для набора данных +/// +public enum PropTypeEnum +{ + /// + String = 0, + /// + Double = 1, + /// + DateTime = 2 +} diff --git a/DD.Persistence/Services/TimestampedValuesService.cs b/DD.Persistence/Services/TimestampedValuesService.cs index cbcb73c..fc17777 100644 --- a/DD.Persistence/Services/TimestampedValuesService.cs +++ b/DD.Persistence/Services/TimestampedValuesService.cs @@ -1,6 +1,5 @@ using DD.Persistence.Extensions; using DD.Persistence.Models; -using DD.Persistence.Models.Common; using DD.Persistence.Repositories; using DD.Persistence.Services.Interfaces; @@ -25,8 +24,7 @@ public class TimestampedValuesService : ITimestampedValuesService // ToDo: реализовать без foreach foreach (var dto in dtos) { - var keys = dto.Values.Keys.ToArray(); - await CreateSystemSpecificationIfNotExist(discriminatorId, keys, token); + await CreateDataSchemeIfNotExist(discriminatorId, dto, token); } var result = await timestampedValuesRepository.AddRange(discriminatorId, dtos, token); @@ -94,7 +92,7 @@ public class TimestampedValuesService : ITimestampedValuesService public async Task> GetGtDate(Guid discriminatorId, DateTimeOffset beginTimestamp, CancellationToken token) { var result = await timestampedValuesRepository.GetGtDate(discriminatorId, beginTimestamp, token); - + var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); var dtos = await Materialize(resultToMaterialize, token); @@ -140,37 +138,69 @@ public class TimestampedValuesService : ITimestampedValuesService } /// - /// Создать спецификацию, при отсутствии таковой + /// Создать схему данных, при отсутствии таковой /// - /// Дискриминатор системы - /// Набор наименований полей + /// Дискриминатор схемы + /// Набор данных, по образу которого будет создана соответствующая схема /// /// /// Некорректный набор наименований полей - private async Task CreateSystemSpecificationIfNotExist(Guid discriminatorId, string[] fieldNames, CancellationToken token) + private async Task CreateDataSchemeIfNotExist(Guid discriminatorId, TimestampedValuesDto dto, CancellationToken token) { - var systemSpecification = await dataSchemeRepository.Get(discriminatorId, token); - if (systemSpecification is null) + var propNames = dto.Values.Keys.ToArray(); + var propTypes = GetPropTypes(dto); + + var dataScheme = await dataSchemeRepository.Get(discriminatorId, token); + if (dataScheme is null) { - systemSpecification = new DataSchemeDto() + dataScheme = new DataSchemeDto() { DiscriminatorId = discriminatorId, - PropNames = fieldNames + PropNames = propNames, + PropTypes = propTypes }; - await dataSchemeRepository.Add(systemSpecification, token); + await dataSchemeRepository.Add(dataScheme, token); return; } - if (!systemSpecification.PropNames.SequenceEqual(fieldNames)) + if (!dataScheme.PropNames.SequenceEqual(propNames)) { - var expectedFieldNames = string.Join(", ", systemSpecification.PropNames); - var actualFieldNames = string.Join(", ", fieldNames); + var expectedFieldNames = string.Join(", ", dataScheme.PropNames); + var actualFieldNames = string.Join(", ", propNames); throw new InvalidOperationException($"Для системы {discriminatorId.ToString()} " + $"характерен набор данных: [{expectedFieldNames}], однако был передан набор: [{actualFieldNames}]"); } } + /// + /// Получить типы для набора данных в соответствии с индексацией + /// + /// + /// + /// + private PropTypeEnum[] GetPropTypes(TimestampedValuesDto dto) + { + var types = dto.Values.Select(e => + { + var valueString = e.Value.ToString(); + + if (valueString is null) + throw new ArgumentNullException("Переданный набор данных содержит null, в следствии чего не удаётся определить типы полей"); + + if (DateTimeOffset.TryParse(valueString, out _)) + return PropTypeEnum.DateTime; + + var doubleString = valueString.Replace('.', ','); + if (double.TryParse(doubleString, out _)) + return PropTypeEnum.Double; + + return PropTypeEnum.String; + }); + + return types.ToArray(); + } + /// /// Отсеить лишние поля в соответствии с заданным фильтром /// From e3c1d02650371eedf299ba3f71b79432f0b18932 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 10:58:26 +0500 Subject: [PATCH 05/13] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TimestampedValuesServiceShould.cs | 5 ++--- .../TreeBuilder/Abstractions/ITreeBuilder.cs | 16 ---------------- 2 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs diff --git a/DD.Persistence.Test/TimestampedValuesServiceShould.cs b/DD.Persistence.Test/TimestampedValuesServiceShould.cs index 0acb6de..165d4e0 100644 --- a/DD.Persistence.Test/TimestampedValuesServiceShould.cs +++ b/DD.Persistence.Test/TimestampedValuesServiceShould.cs @@ -3,12 +3,12 @@ using DD.Persistence.Repositories; using DD.Persistence.Services; using NSubstitute; -namespace DD.Persistence.Repository.Test; +namespace DD.Persistence.Test; public class TimestampedValuesServiceShould { private readonly ITimestampedValuesRepository timestampedValuesRepository = Substitute.For(); private readonly IDataSchemeRepository dataSchemeRepository = Substitute.For(); - private TimestampedValuesService timestampedValuesService; + private readonly TimestampedValuesService timestampedValuesService; public TimestampedValuesServiceShould() { @@ -40,7 +40,6 @@ public class TimestampedValuesServiceShould private static IEnumerable Generate(int countToCreate, DateTimeOffset from) { - var result = new List(); for (int i = 0; i < countToCreate; i++) { var values = new Dictionary() diff --git a/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs b/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs deleted file mode 100644 index b512a53..0000000 --- a/DD.Persistence/Filter/TreeBuilder/Abstractions/ITreeBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using DD.Persistence.Filter.Models.Abstractions; - -namespace DD.Persistence.Filter.Interpreter.Abstractions; - -/// -/// Интерпретатор для построения дерева -/// -public interface ITreeBuilder -{ - /// - /// Построить дерево - /// - /// Дерево в виде строки - /// Корень дерева в виде вершины - TNode? Build(string treeString); -} \ No newline at end of file From 560073ed07cfd172bfd4941dd89e0c46d6e80e2b Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 11:45:47 +0500 Subject: [PATCH 06/13] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20#2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TreeBuilder/Expressions/Abstractions/IExpression.cs | 8 ++++---- .../NonTerminal/Abstractions/NonTerminalExpression.cs | 2 +- .../TreeBuilder/Expressions/NonTerminal/AndExpression.cs | 2 +- .../TreeBuilder/Expressions/NonTerminal/OrExpression.cs | 2 +- .../Expressions/Terminal/Abstract/TerminalExpression.cs | 2 +- .../TreeBuilder/Expressions/Terminal/EqualExpression.cs | 2 +- .../TreeBuilder/Expressions/Terminal/LessExpression.cs | 2 +- .../Expressions/Terminal/LessOrEqualExpression.cs | 2 +- .../TreeBuilder/Expressions/Terminal/MoreExpression.cs | 2 +- .../Expressions/Terminal/MoreOrEqualExpression.cs | 2 +- .../Expressions/Terminal/NotEqualExpression.cs | 2 +- DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs index b28bde8..c1418bf 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs @@ -5,23 +5,23 @@ namespace DD.Persistence.Filter.Interpreter.Expressions.Abstract; /// /// Интерфейс для выражений /// -public interface IExpression +interface IExpression { /// /// Получить логическую операцию /// /// - public OperationEnum GetOperation(); + OperationEnum GetOperation(); /// /// Получить логическую операцию в виде строки (для регулярных выражений) /// /// - public string GetOperationString(); + string GetOperationString(); /// /// Реализация правила /// /// - public void Interpret(InterpreterContext context); + void Interpret(InterpreterContext context); } diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs index 137ec4b..d543b8b 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs @@ -9,7 +9,7 @@ namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base; /// /// Абстрактный класс для нетерминальных выражений /// -public abstract class NonTerminalExpression : IExpression +abstract class NonTerminalExpression : IExpression { /// /// Реализация правила для нетерминальных выражений diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs index 4a3d363..599315c 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal; /// /// Выражение для "И" /// -public class AndExpression : NonTerminalExpression +class AndExpression : NonTerminalExpression { private const string AndString = "&&"; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs index e47b935..6aa6c69 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal; /// /// Выражение для "ИЛИ" /// -public class OrExpression : NonTerminalExpression +class OrExpression : NonTerminalExpression { private const string OrString = @"\|\|"; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs index ada1f56..5d2caed 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs @@ -9,7 +9,7 @@ namespace DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; /// /// Абстрактный класс для терминальных выражений /// -public abstract class TerminalExpression : IExpression +abstract class TerminalExpression : IExpression { /// /// Реализация правила для терминальных выражений diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs index 4c78e36..aec5a6b 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; /// /// Выражение для "РАВНО" /// -public class EqualExpression : TerminalExpression +class EqualExpression : TerminalExpression { private const string EqualString = "=="; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs index a7e6902..7382e87 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; /// /// Выражение для "МЕНЬШЕ" /// -public class LessExpression : TerminalExpression +class LessExpression : TerminalExpression { private const string EqualString = "<"; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs index 9a5c6be..c706843 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; /// /// Выражение для "МЕНЬШЕ ЛИБО РАВНО" /// -public class LessOrEqualExpression : TerminalExpression +class LessOrEqualExpression : TerminalExpression { private const string EqualString = "<="; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs index 0d6c8b0..cbc3d82 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; /// /// Выражение для "БОЛЬШЕ" /// -public class MoreExpression : TerminalExpression +class MoreExpression : TerminalExpression { private const string EqualString = ">"; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs index 1dd2db4..a6a8345 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; /// /// Выражение для "БОЛЬШЕ ЛИБО РАВНО" /// -public class MoreOrEqualExpression : TerminalExpression +class MoreOrEqualExpression : TerminalExpression { private const string EqualString = ">="; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs index b51817a..49031f1 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs @@ -6,7 +6,7 @@ namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; /// /// Выражение для "НЕРАВНО" /// -public class NotEqualExpression : TerminalExpression +class NotEqualExpression : TerminalExpression { private const string NotEqulString = "!="; diff --git a/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs index 72e0384..86e0ef8 100644 --- a/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs +++ b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs @@ -5,7 +5,7 @@ namespace DD.Persistence.Filter.Interpreter; /// /// Контекст интерпретатора /// -public class InterpreterContext +class InterpreterContext { /// /// Корень дерева (результат интерпретации) From 63e6816e350c49b50859e3fed31771c490089f1a Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 12:10:01 +0500 Subject: [PATCH 07/13] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20#3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SetpointRepositoryShould.cs | 1 - ...reeBuilderShould.cs => TreeBuilderTest.cs} | 12 +++---- .../Expressions/Abstractions/IExpression.cs | 2 +- .../Abstractions/NonTerminalExpression.cs | 34 +++++++++---------- .../Expressions/NonTerminal/AndExpression.cs | 6 ++-- .../Expressions/NonTerminal/OrExpression.cs | 6 ++-- .../Terminal/Abstract/TerminalExpression.cs | 20 +++++------ .../Expressions/Terminal/EqualExpression.cs | 4 +-- .../Expressions/Terminal/LessExpression.cs | 4 +-- .../Terminal/LessOrEqualExpression.cs | 4 +-- .../Expressions/Terminal/MoreExpression.cs | 4 +-- .../Terminal/MoreOrEqualExpression.cs | 4 +-- .../Terminal/NotEqualExpression.cs | 4 +-- .../{TreeBuilder.cs => FilterTreeBuilder.cs} | 34 ++++++++++--------- .../Filter/TreeBuilder/InterpreterContext.cs | 10 +++--- 15 files changed, 75 insertions(+), 74 deletions(-) rename DD.Persistence.Test/{TreeBuilderShould.cs => TreeBuilderTest.cs} (93%) rename DD.Persistence/Filter/TreeBuilder/{TreeBuilder.cs => FilterTreeBuilder.cs} (58%) diff --git a/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs b/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs index 6b05ff3..c9f6088 100644 --- a/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs +++ b/DD.Persistence.Repository.Test/SetpointRepositoryShould.cs @@ -29,7 +29,6 @@ public class SetpointRepositoryShould : IClassFixture var value = GetJsonFromObject(22); await sut.Add(id, value, Guid.NewGuid(), CancellationToken.None); - var t = fixture.dbContainer.GetConnectionString(); //act var result = await sut.GetCurrent([id], CancellationToken.None); diff --git a/DD.Persistence.Test/TreeBuilderShould.cs b/DD.Persistence.Test/TreeBuilderTest.cs similarity index 93% rename from DD.Persistence.Test/TreeBuilderShould.cs rename to DD.Persistence.Test/TreeBuilderTest.cs index f96f85b..1259ca7 100644 --- a/DD.Persistence.Test/TreeBuilderShould.cs +++ b/DD.Persistence.Test/TreeBuilderTest.cs @@ -1,13 +1,13 @@ -using DD.Persistence.Filter.Interpreter; -using DD.Persistence.Filter.Models; +using DD.Persistence.Filter.Models; using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder; using Newtonsoft.Json; namespace DD.Persistence.Test; -public class TreeBuilderShould +public class TreeBuilderTest { [Fact] - public void TestTreeBuilding() + public void TreeBuildingShouldBuilt() { //arrange var treeString = "(\"A\"==1)||(\"B\"==2)&&(\"C\"==3)||((\"D\"==4)||(\"E\"==5))&&(\"F\"==6)"; @@ -44,7 +44,7 @@ public class TreeBuilderShould } [Fact] - public void TestTreeOperations() + public void TreeOperationsShouldBuilt() { //arrange var treeString = "(\"A\"==1)||(\"B\"!=1)||(\"C\">1)||(\"D\">=1)||(\"E\"<1)||(\"F\"<=1)"; @@ -81,7 +81,7 @@ public class TreeBuilderShould } [Fact] - public void TestLeafValues() + public void LeafValuesShouldBuilt() { //arrange var treeString = "(\"A\"==1.2345)||(\"B\"==12345)||(\"C\"==\"12345\")"; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs index c1418bf..8a5a526 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Abstractions/IExpression.cs @@ -1,6 +1,6 @@ using DD.Persistence.Filter.Models.Enumerations; -namespace DD.Persistence.Filter.Interpreter.Expressions.Abstract; +namespace DD.Persistence.Filter.TreeBuilder.Expressions.Abstractions; /// /// Интерфейс для выражений diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs index d543b8b..5ce524b 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/Abstractions/NonTerminalExpression.cs @@ -1,10 +1,10 @@ using DD.Persistence.Extensions; -using DD.Persistence.Filter.Interpreter.Expressions.Abstract; using DD.Persistence.Filter.Models; using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.Abstractions; using System.Text.RegularExpressions; -namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base; +namespace DD.Persistence.Filter.TreeBuilder.Expressions.NonTerminal.Abstractions; /// /// Абстрактный класс для нетерминальных выражений @@ -20,8 +20,8 @@ abstract class NonTerminalExpression : IExpression var operation = GetOperation(); var operationString = GetOperationString(); - var matches = GetMatches(context, operation, operationString); - while (matches.Any()) + var matches = GetMatches(context, operationString); + while (matches.Length != 0) { matches.ForEach(m => { @@ -33,29 +33,29 @@ abstract class NonTerminalExpression : IExpression .Split(separator) .Select(e => int.Parse(e)); - var leftNode = context.treeNodes + var leftNode = context.TreeNodes .FirstOrDefault(e => e.Key == pair.First()) .Value; - var rigthNode = context.treeNodes + var rigthNode = context.TreeNodes .FirstOrDefault(e => e.Key == pair.Last()) .Value; var node = new TVertex(operation, leftNode, rigthNode); - var key = context.treeNodes.Count(); - context.treeNodes.Add(key, node); + var key = context.TreeNodes.Count; + context.TreeNodes.Add(key, node); var keyString = key.ToString(); - context.treeString = context.treeString.Replace(matchString, keyString); + context.TreeString = context.TreeString.Replace(matchString, keyString); }); - matches = GetMatches(context, operation, operationString); + matches = GetMatches(context, operationString); } - var isRoot = int.TryParse(context.treeString, out _); + var isRoot = int.TryParse(context.TreeString, out _); if (isRoot) { - context.treeString = string.Empty; - context.root = context.treeNodes.Last().Value; + context.TreeString = string.Empty; + context.Root = context.TreeNodes.Last().Value; } } @@ -69,13 +69,13 @@ abstract class NonTerminalExpression : IExpression /// /// Получить из акткуального состояния строки все совпадения для текущего выражения /// - private IEnumerable GetMatches(InterpreterContext context, OperationEnum operation, string operationString) + private static Match[] GetMatches(InterpreterContext context, string operationString) { - string pattern = context.treeString.Contains('(') && context.treeString.Contains(')') + string pattern = context.TreeString.Contains('(') && context.TreeString.Contains(')') ? $@"\(\d+{operationString}\d+\)" : $@"\d+{operationString}\d+"; - Regex regex = new Regex(pattern); + Regex regex = new(pattern); var matches = regex - .Matches(context.treeString) + .Matches(context.TreeString) .ToArray(); return matches; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs index 599315c..9af8dbe 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/AndExpression.cs @@ -1,7 +1,7 @@ -using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base; -using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.NonTerminal.Abstractions; -namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal; +namespace DD.Persistence.Filter.TreeBuilder.Expressions.NonTerminal; /// /// Выражение для "И" diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs index 6aa6c69..4be21bf 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/NonTerminal/OrExpression.cs @@ -1,7 +1,7 @@ -using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal.Base; -using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.NonTerminal.Abstractions; -namespace DD.Persistence.Filter.Interpreter.Expressions.NonTerminal; +namespace DD.Persistence.Filter.TreeBuilder.Expressions.NonTerminal; /// /// Выражение для "ИЛИ" diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs index 5d2caed..1d13d6b 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/Abstract/TerminalExpression.cs @@ -1,10 +1,10 @@ using DD.Persistence.Extensions; -using DD.Persistence.Filter.Interpreter.Expressions.Abstract; using DD.Persistence.Filter.Models; using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.Abstractions; using System.Text.RegularExpressions; -namespace DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; +namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal.Abstract; /// /// Абстрактный класс для терминальных выражений @@ -20,7 +20,7 @@ abstract class TerminalExpression : IExpression var operation = GetOperation(); var operationString = GetOperationString(); - var matches = GetMatches(context, operation, operationString); + var matches = GetMatches(context, operationString); matches.ForEach(m => { var matchString = m.ToString(); @@ -34,11 +34,11 @@ abstract class TerminalExpression : IExpression var value = ParseValue(pair.Last()); var node = new TLeaf(operation, fieldName, value); - var key = context.treeNodes.Count(); - context.treeNodes.Add(key, node); + var key = context.TreeNodes.Count; + context.TreeNodes.Add(key, node); var keyString = key.ToString(); - context.treeString = context.treeString.Replace(matchString, keyString); + context.TreeString = context.TreeString.Replace(matchString, keyString); }); } @@ -51,16 +51,16 @@ abstract class TerminalExpression : IExpression /// /// Получить из акткуального состояния строки все совпадения для текущего выражения /// - private IEnumerable GetMatches(InterpreterContext context, OperationEnum operation, string operationString) + private static Match[] GetMatches(InterpreterContext context, string operationString) { string pattern = $@"\([^()]*{operationString}.*?\)"; - Regex regex = new Regex(pattern); - var matches = regex.Matches(context.treeString); + Regex regex = new(pattern); + var matches = regex.Matches(context.TreeString).ToArray(); return matches; } - private object? ParseValue(string value) + private static object? ParseValue(string value) { value = value.Replace('.', ','); if (value.Contains(',') && double.TryParse(value, out _)) diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs index aec5a6b..3c79045 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/EqualExpression.cs @@ -1,5 +1,5 @@ -using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; -using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal.Abstract; namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs index 7382e87..dbbdf3c 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessExpression.cs @@ -1,5 +1,5 @@ -using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; -using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal.Abstract; namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs index c706843..c9514e5 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/LessOrEqualExpression.cs @@ -1,5 +1,5 @@ -using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; -using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal.Abstract; namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs index cbc3d82..6cdca36 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreExpression.cs @@ -1,5 +1,5 @@ -using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; -using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal.Abstract; namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs index a6a8345..d0e13e3 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/MoreOrEqualExpression.cs @@ -1,5 +1,5 @@ -using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; -using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal.Abstract; namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; diff --git a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs index 49031f1..66662c6 100644 --- a/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs +++ b/DD.Persistence/Filter/TreeBuilder/Expressions/Terminal/NotEqualExpression.cs @@ -1,5 +1,5 @@ -using DD.Persistence.Filter.Interpreter.Expressions.Terminal.Base; -using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.Models.Enumerations; +using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal.Abstract; namespace DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; diff --git a/DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs b/DD.Persistence/Filter/TreeBuilder/FilterTreeBuilder.cs similarity index 58% rename from DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs rename to DD.Persistence/Filter/TreeBuilder/FilterTreeBuilder.cs index 224c74c..4112e21 100644 --- a/DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs +++ b/DD.Persistence/Filter/TreeBuilder/FilterTreeBuilder.cs @@ -1,14 +1,14 @@ -using DD.Persistence.Filter.Interpreter.Expressions.Abstract; -using DD.Persistence.Filter.Interpreter.Expressions.NonTerminal; -using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Filter.Models.Abstractions; +using DD.Persistence.Filter.TreeBuilder.Expressions.Abstractions; +using DD.Persistence.Filter.TreeBuilder.Expressions.NonTerminal; using DD.Persistence.Filter.TreeBuilder.Expressions.Terminal; -namespace DD.Persistence.Filter.Interpreter; +namespace DD.Persistence.Filter.TreeBuilder; /// /// Строитель бинарных деревьев /// -public static class TreeBuilder +public static class FilterTreeBuilder { /// @@ -18,35 +18,37 @@ public static class TreeBuilder /// public static TNode? BuildTree(this string treeString) { - InterpreterContext context = new InterpreterContext(treeString); + InterpreterContext context = new(treeString); // Порядок важен - List terminalExpressions = new List - { + List terminalExpressions = + [ new EqualExpression(), new NotEqualExpression(), new MoreOrEqualExpression(), new LessOrEqualExpression(), new MoreExpression(), new LessExpression() - }; - terminalExpressions.ForEach(e => { + ]; + terminalExpressions.ForEach(e => + { e.Interpret(context); }); // Порядок важен - List nonTerminalExpressions = new List - { + List nonTerminalExpressions = + [ new OrExpression(), new AndExpression() - }; - while (!string.IsNullOrEmpty(context.treeString)) + ]; + while (!string.IsNullOrEmpty(context.TreeString)) { - nonTerminalExpressions.ForEach(e => { + nonTerminalExpressions.ForEach(e => + { e.Interpret(context); }); } - return context.root; + return context.Root; } } diff --git a/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs index 86e0ef8..3471f8d 100644 --- a/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs +++ b/DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs @@ -1,6 +1,6 @@ using DD.Persistence.Filter.Models.Abstractions; -namespace DD.Persistence.Filter.Interpreter; +namespace DD.Persistence.Filter.TreeBuilder; /// /// Контекст интерпретатора @@ -10,21 +10,21 @@ class InterpreterContext /// /// Корень дерева (результат интерпретации) /// - public TNode? root { get; set; } + public TNode? Root { get; set; } /// /// Дерево в виде строки (входной параметр) /// - public string treeString { get; set; } + public string TreeString { get; set; } /// /// Проиндексированные вершины дерева /// - public Dictionary treeNodes { get; set; } = []; + public Dictionary TreeNodes { get; set; } = []; /// public InterpreterContext(string theeString) { - this.treeString = theeString; + TreeString = theeString; } } From 4513de06fa1d532aef0a6d0cd9403aab8dd2aed3 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 12:19:45 +0500 Subject: [PATCH 08/13] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20=D1=81=D0=BE=D0=B4=D0=B5=D1=80=D0=B6=D0=B8?= =?UTF-8?q?=D0=BC=D0=BE=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0?= =?UTF-8?q?=20DD.Persistence.Repository=20=D0=B2=20DD.Persistence.Database?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.API/Startup.cs | 3 +- .../DD.Persistence.Database.Postgres.csproj | 2 - .../DependencyInjection.cs | 33 ------------- .../DD.Persistence.Database.csproj | 2 + .../DependencyInjection.cs | 47 +++++++++++++++++++ .../Extensions/EFExtensionsSortBy.cs | 2 +- .../Helpers/CyclicArray.cs | 0 .../Helpers/QueryBuilders.cs | 0 .../Repositories/ChangeLogRepository.cs | 8 ++-- .../Repositories/DataSchemeRepository.cs | 0 .../DataSourceSystemRepository.cs | 0 .../Repositories/ParameterRepository.cs | 0 .../Repositories/SetpointRepository.cs | 0 .../Repositories/TechMessagesRepository.cs | 0 .../TimestampedValuesRepository.cs | 0 .../DataSchemeCachedRepository.cs | 0 .../DataSourceSystemCachedRepository.cs | 0 .../TimestampedValuesCachedRepository.cs | 0 18 files changed, 56 insertions(+), 41 deletions(-) create mode 100644 DD.Persistence.Database/DependencyInjection.cs rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Extensions/EFExtensionsSortBy.cs (99%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Helpers/CyclicArray.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Helpers/QueryBuilders.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Repositories/ChangeLogRepository.cs (96%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Repositories/DataSchemeRepository.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Repositories/DataSourceSystemRepository.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Repositories/ParameterRepository.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Repositories/SetpointRepository.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Repositories/TechMessagesRepository.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/Repositories/TimestampedValuesRepository.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/RepositoriesCached/DataSchemeCachedRepository.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/RepositoriesCached/DataSourceSystemCachedRepository.cs (100%) rename {DD.Persistence.Database.Postgres => DD.Persistence.Database}/RepositoriesCached/TimestampedValuesCachedRepository.cs (100%) diff --git a/DD.Persistence.API/Startup.cs b/DD.Persistence.API/Startup.cs index bc78548..a3c3efe 100644 --- a/DD.Persistence.API/Startup.cs +++ b/DD.Persistence.API/Startup.cs @@ -1,4 +1,5 @@ -using DD.Persistence.Database.Model; +using DD.Persistence.Database; +using DD.Persistence.Database.Model; using DD.Persistence.Database.Postgres.Extensions; namespace DD.Persistence.API; diff --git a/DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj b/DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj index 80b6736..bf406a6 100644 --- a/DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj +++ b/DD.Persistence.Database.Postgres/DD.Persistence.Database.Postgres.csproj @@ -7,13 +7,11 @@ - all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/DD.Persistence.Database.Postgres/DependencyInjection.cs b/DD.Persistence.Database.Postgres/DependencyInjection.cs index 0509061..df84bb3 100644 --- a/DD.Persistence.Database.Postgres/DependencyInjection.cs +++ b/DD.Persistence.Database.Postgres/DependencyInjection.cs @@ -24,37 +24,4 @@ public static class DependencyInjection return services; } - - public static void MapsterSetup() - { - TypeAdapterConfig.GlobalSettings.Default.Config - .ForType() - .Ignore(dest => dest.System, dest => dest.SystemId); - - TypeAdapterConfig.NewConfig() - .Map(dest => dest.Value, src => new ChangeLogValuesDto() - { - Value = src.Value, - Id = src.Id - }); - } - - public static IServiceCollection AddInfrastructure(this IServiceCollection services) - { - var typeAdapterConfig = TypeAdapterConfig.GlobalSettings; - typeAdapterConfig.RuleMap.Clear(); - typeAdapterConfig.Scan(Assembly.GetExecutingAssembly()); - - MapsterSetup(); - - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - return services; - } } diff --git a/DD.Persistence.Database/DD.Persistence.Database.csproj b/DD.Persistence.Database/DD.Persistence.Database.csproj index 9303e6a..65f8d54 100644 --- a/DD.Persistence.Database/DD.Persistence.Database.csproj +++ b/DD.Persistence.Database/DD.Persistence.Database.csproj @@ -7,11 +7,13 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/DD.Persistence.Database/DependencyInjection.cs b/DD.Persistence.Database/DependencyInjection.cs new file mode 100644 index 0000000..c04d9e5 --- /dev/null +++ b/DD.Persistence.Database/DependencyInjection.cs @@ -0,0 +1,47 @@ +using DD.Persistence.Database.Entity; +using DD.Persistence.Database.Postgres.Repositories; +using DD.Persistence.Database.Postgres.RepositoriesCached; +using DD.Persistence.Database.Repositories; +using DD.Persistence.Models; +using DD.Persistence.Repositories; +using Mapster; +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; + +namespace DD.Persistence.Database; + +public static class DependencyInjection +{ + public static void MapsterSetup() + { + TypeAdapterConfig.GlobalSettings.Default.Config + .ForType() + .Ignore(dest => dest.System, dest => dest.SystemId); + + TypeAdapterConfig.NewConfig() + .Map(dest => dest.Value, src => new ChangeLogValuesDto() + { + Value = src.Value, + Id = src.Id + }); + } + + public static IServiceCollection AddInfrastructure(this IServiceCollection services) + { + var typeAdapterConfig = TypeAdapterConfig.GlobalSettings; + typeAdapterConfig.RuleMap.Clear(); + typeAdapterConfig.Scan(Assembly.GetExecutingAssembly()); + + MapsterSetup(); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + return services; + } +} diff --git a/DD.Persistence.Database.Postgres/Extensions/EFExtensionsSortBy.cs b/DD.Persistence.Database/Extensions/EFExtensionsSortBy.cs similarity index 99% rename from DD.Persistence.Database.Postgres/Extensions/EFExtensionsSortBy.cs rename to DD.Persistence.Database/Extensions/EFExtensionsSortBy.cs index 3af7ae0..10818a4 100644 --- a/DD.Persistence.Database.Postgres/Extensions/EFExtensionsSortBy.cs +++ b/DD.Persistence.Database/Extensions/EFExtensionsSortBy.cs @@ -2,7 +2,7 @@ using System.Collections.Concurrent; using System.Linq.Expressions; using System.Reflection; -namespace DD.Persistence.Database.Postgres.Extensions; +namespace DD.Persistence.Database.Extensions; public static class EFExtensionsSortBy { diff --git a/DD.Persistence.Database.Postgres/Helpers/CyclicArray.cs b/DD.Persistence.Database/Helpers/CyclicArray.cs similarity index 100% rename from DD.Persistence.Database.Postgres/Helpers/CyclicArray.cs rename to DD.Persistence.Database/Helpers/CyclicArray.cs diff --git a/DD.Persistence.Database.Postgres/Helpers/QueryBuilders.cs b/DD.Persistence.Database/Helpers/QueryBuilders.cs similarity index 100% rename from DD.Persistence.Database.Postgres/Helpers/QueryBuilders.cs rename to DD.Persistence.Database/Helpers/QueryBuilders.cs diff --git a/DD.Persistence.Database.Postgres/Repositories/ChangeLogRepository.cs b/DD.Persistence.Database/Repositories/ChangeLogRepository.cs similarity index 96% rename from DD.Persistence.Database.Postgres/Repositories/ChangeLogRepository.cs rename to DD.Persistence.Database/Repositories/ChangeLogRepository.cs index c2502ef..61e907d 100644 --- a/DD.Persistence.Database.Postgres/Repositories/ChangeLogRepository.cs +++ b/DD.Persistence.Database/Repositories/ChangeLogRepository.cs @@ -8,7 +8,7 @@ using Mapster; using Microsoft.EntityFrameworkCore; using UuidExtensions; -namespace DD.Persistence.Database.Postgres.Repositories; +namespace DD.Persistence.Database.Repositories; public class ChangeLogRepository : IChangeLogRepository { private readonly DbContext db; @@ -186,7 +186,7 @@ public class ChangeLogRepository : IChangeLogRepository var datesUpdate = await datesUpdateQuery.ToArrayAsync(token); - var dates = Enumerable.Concat(datesCreate, datesUpdate); + var dates = datesCreate.Concat(datesUpdate); var datesOnly = dates .Select(d => new DateOnly(d.Year, d.Month, d.Day)) .Distinct() @@ -214,7 +214,7 @@ public class ChangeLogRepository : IChangeLogRepository public async Task> GetGtDate(Guid idDiscriminator, DateTimeOffset dateBegin, CancellationToken token) { var date = dateBegin.ToUniversalTime(); - var query = this.db.Set() + var query = db.Set() .Where(e => e.IdDiscriminator == idDiscriminator) .Where(e => e.Creation >= date || e.Obsolete >= date); @@ -233,7 +233,7 @@ public class ChangeLogRepository : IChangeLogRepository .Select(group => new { Min = group.Min(e => e.Creation), - Max = group.Max(e => (e.Obsolete.HasValue && e.Obsolete > e.Creation) + Max = group.Max(e => e.Obsolete.HasValue && e.Obsolete > e.Creation ? e.Obsolete.Value : e.Creation), }); diff --git a/DD.Persistence.Database.Postgres/Repositories/DataSchemeRepository.cs b/DD.Persistence.Database/Repositories/DataSchemeRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/Repositories/DataSchemeRepository.cs rename to DD.Persistence.Database/Repositories/DataSchemeRepository.cs diff --git a/DD.Persistence.Database.Postgres/Repositories/DataSourceSystemRepository.cs b/DD.Persistence.Database/Repositories/DataSourceSystemRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/Repositories/DataSourceSystemRepository.cs rename to DD.Persistence.Database/Repositories/DataSourceSystemRepository.cs diff --git a/DD.Persistence.Database.Postgres/Repositories/ParameterRepository.cs b/DD.Persistence.Database/Repositories/ParameterRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/Repositories/ParameterRepository.cs rename to DD.Persistence.Database/Repositories/ParameterRepository.cs diff --git a/DD.Persistence.Database.Postgres/Repositories/SetpointRepository.cs b/DD.Persistence.Database/Repositories/SetpointRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/Repositories/SetpointRepository.cs rename to DD.Persistence.Database/Repositories/SetpointRepository.cs diff --git a/DD.Persistence.Database.Postgres/Repositories/TechMessagesRepository.cs b/DD.Persistence.Database/Repositories/TechMessagesRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/Repositories/TechMessagesRepository.cs rename to DD.Persistence.Database/Repositories/TechMessagesRepository.cs diff --git a/DD.Persistence.Database.Postgres/Repositories/TimestampedValuesRepository.cs b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/Repositories/TimestampedValuesRepository.cs rename to DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs diff --git a/DD.Persistence.Database.Postgres/RepositoriesCached/DataSchemeCachedRepository.cs b/DD.Persistence.Database/RepositoriesCached/DataSchemeCachedRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/RepositoriesCached/DataSchemeCachedRepository.cs rename to DD.Persistence.Database/RepositoriesCached/DataSchemeCachedRepository.cs diff --git a/DD.Persistence.Database.Postgres/RepositoriesCached/DataSourceSystemCachedRepository.cs b/DD.Persistence.Database/RepositoriesCached/DataSourceSystemCachedRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/RepositoriesCached/DataSourceSystemCachedRepository.cs rename to DD.Persistence.Database/RepositoriesCached/DataSourceSystemCachedRepository.cs diff --git a/DD.Persistence.Database.Postgres/RepositoriesCached/TimestampedValuesCachedRepository.cs b/DD.Persistence.Database/RepositoriesCached/TimestampedValuesCachedRepository.cs similarity index 100% rename from DD.Persistence.Database.Postgres/RepositoriesCached/TimestampedValuesCachedRepository.cs rename to DD.Persistence.Database/RepositoriesCached/TimestampedValuesCachedRepository.cs From 431c7278cb7ff63c66c764739617515c47cbbda4 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 14:30:36 +0500 Subject: [PATCH 09/13] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.Database/Entity/DataScheme.cs | 23 +++++++++++-------- .../TimestampedValuesRepository.cs | 9 -------- .../Services/TimestampedValuesService.cs | 3 +++ 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/DD.Persistence.Database/Entity/DataScheme.cs b/DD.Persistence.Database/Entity/DataScheme.cs index a231580..3ce46a2 100644 --- a/DD.Persistence.Database/Entity/DataScheme.cs +++ b/DD.Persistence.Database/Entity/DataScheme.cs @@ -1,19 +1,22 @@ -using DD.Persistence.Models; -using Microsoft.EntityFrameworkCore; -using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json; namespace DD.Persistence.Database.Entity; -[Table("data_scheme")] -public class DataScheme +[Table("prop_scheme")] +[PrimaryKey(nameof(DiscriminatorId), nameof(Index))] +public class PropScheme { - [Key, Comment("Идентификатор схемы данных"),] + [Comment("Идентификатор схемы данных")] public Guid DiscriminatorId { get; set; } - [Comment("Наименования полей в порядке индексации"), Column(TypeName = "jsonb")] - public string[] PropNames { get; set; } = []; + [Comment("Индекс поля")] + public int Index { get; set; } - [Comment("Типы полей в порядке индексации")] - public PropTypeEnum[] PropTypes { get; set; } = []; + [Comment("Наименования индексируемого поля")] + public required string PropName { get; set; } + + [Comment("Тип индексируемого поля")] + public required JsonValueKind PropKind { get; set; } } diff --git a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs index 149e411..1239b4a 100644 --- a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs +++ b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs @@ -55,15 +55,6 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository .Select(g => KeyValuePair.Create(g.Key, g.OrderBy(i => i.Timestamp).Skip(skip).Take(take))); var entities = await groupQuery.ToArrayAsync(token); - //var root = new TVertex( - // OperationEnum.And, - // new TLeaf(OperationEnum.Equal, "A", 1), - // new TLeaf(OperationEnum.Equal, "B", 1) - //); - //var dataScheme = entities.First().Value.First().DataScheme; - //var specification = dataScheme.BuildFilter(root); - //var que = ApplySpecification(specification); - var result = entities.ToDictionary(k => k.Key, v => v.Value.Select(e => ( e.Timestamp, e.Values diff --git a/DD.Persistence/Services/TimestampedValuesService.cs b/DD.Persistence/Services/TimestampedValuesService.cs index fc17777..264fdc5 100644 --- a/DD.Persistence/Services/TimestampedValuesService.cs +++ b/DD.Persistence/Services/TimestampedValuesService.cs @@ -2,6 +2,7 @@ using DD.Persistence.Models; using DD.Persistence.Repositories; using DD.Persistence.Services.Interfaces; +using System.Text.Json; namespace DD.Persistence.Services; @@ -100,6 +101,7 @@ public class TimestampedValuesService : ITimestampedValuesService return dtos; } + // ToDo: рефакторинг, переименовать (текущее название не отражает суть) /// /// Преобразовать результат запроса в набор dto /// @@ -183,6 +185,7 @@ public class TimestampedValuesService : ITimestampedValuesService { var types = dto.Values.Select(e => { + var objectKind = ((JsonElement) e.Value).ValueKind; var valueString = e.Value.ToString(); if (valueString is null) From 9ca49cb1b517355b74d2d7fcece2bb227f60cb36 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Wed, 5 Feb 2025 17:20:18 +0500 Subject: [PATCH 10/13] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20#2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.API/Startup.cs | 2 +- ...ner.cs => 20250205114037_Init.Designer.cs} | 59 ++++++------- ...4044050_Init.cs => 20250205114037_Init.cs} | 39 ++++----- ...PersistencePostgresContextModelSnapshot.cs | 57 ++++++------ .../DependencyInjection.cs | 9 +- .../{DataScheme.cs => SchemeProperty.cs} | 9 +- .../Entity/TimestampedValues.cs | 3 - .../PersistenceDbContext.cs | 6 +- .../Repositories/DataSchemeRepository.cs | 34 -------- .../Repositories/SchemePropertyRepository.cs | 43 ++++++++++ .../TimestampedValuesRepository.cs | 3 +- ...y.cs => SchemePropertyCachedRepository.cs} | 12 +-- .../TimestampedValuesControllerTest.cs | 6 +- DD.Persistence.Models/DataSchemeDto.cs | 36 ++++++-- .../Enumerations/PropTypeEnum.cs | 14 --- DD.Persistence.Models/SchemePropertyDto.cs | 30 +++++++ .../TimestampedValuesServiceShould.cs | 2 +- ...sitory.cs => ISchemePropertyRepository.cs} | 4 +- .../Services/TimestampedValuesService.cs | 86 ++++++------------- 19 files changed, 221 insertions(+), 233 deletions(-) rename DD.Persistence.Database.Postgres/Migrations/{20250204044050_Init.Designer.cs => 20250205114037_Init.Designer.cs} (88%) rename DD.Persistence.Database.Postgres/Migrations/{20250204044050_Init.cs => 20250205114037_Init.cs} (90%) rename DD.Persistence.Database/Entity/{DataScheme.cs => SchemeProperty.cs} (71%) delete mode 100644 DD.Persistence.Database/Repositories/DataSchemeRepository.cs create mode 100644 DD.Persistence.Database/Repositories/SchemePropertyRepository.cs rename DD.Persistence.Database/RepositoriesCached/{DataSchemeCachedRepository.cs => SchemePropertyCachedRepository.cs} (57%) delete mode 100644 DD.Persistence.Models/Enumerations/PropTypeEnum.cs create mode 100644 DD.Persistence.Models/SchemePropertyDto.cs rename DD.Persistence/Repositories/{IDataSchemeRepository.cs => ISchemePropertyRepository.cs} (84%) diff --git a/DD.Persistence.API/Startup.cs b/DD.Persistence.API/Startup.cs index a3c3efe..f19e6cf 100644 --- a/DD.Persistence.API/Startup.cs +++ b/DD.Persistence.API/Startup.cs @@ -14,7 +14,7 @@ public class Startup public void ConfigureServices(IServiceCollection services) { - // Add services to the container. + // AddRange services to the container. services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle diff --git a/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs b/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.Designer.cs similarity index 88% rename from DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs rename to DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.Designer.cs index 60e6e92..b90d452 100644 --- a/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.Designer.cs +++ b/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.Designer.cs @@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace DD.Persistence.Database.Postgres.Migrations { [DbContext(typeof(PersistencePostgresContext))] - [Migration("20250204044050_Init")] + [Migration("20250205114037_Init")] partial class Init { /// @@ -67,28 +67,6 @@ namespace DD.Persistence.Database.Postgres.Migrations b.ToTable("change_log"); }); - modelBuilder.Entity("DD.Persistence.Database.Entity.DataScheme", b => - { - b.Property("DiscriminatorId") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasComment("Идентификатор схемы данных"); - - b.Property("PropNames") - .IsRequired() - .HasColumnType("jsonb") - .HasComment("Наименования полей в порядке индексации"); - - b.PrimitiveCollection("PropTypes") - .IsRequired() - .HasColumnType("integer[]") - .HasComment("Типы полей в порядке индексации"); - - b.HasKey("DiscriminatorId"); - - b.ToTable("data_scheme"); - }); - modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b => { b.Property("SystemId") @@ -134,6 +112,30 @@ namespace DD.Persistence.Database.Postgres.Migrations b.ToTable("parameter_data"); }); + modelBuilder.Entity("DD.Persistence.Database.Entity.SchemeProperty", b => + { + b.Property("DiscriminatorId") + .HasColumnType("uuid") + .HasComment("Идентификатор схемы данных"); + + b.Property("Index") + .HasColumnType("integer") + .HasComment("Индекс поля"); + + b.Property("PropertyKind") + .HasColumnType("smallint") + .HasComment("Тип индексируемого поля"); + + b.Property("PropertyName") + .IsRequired() + .HasColumnType("text") + .HasComment("Наименования индексируемого поля"); + + b.HasKey("DiscriminatorId", "Index"); + + b.ToTable("scheme_property"); + }); + modelBuilder.Entity("DD.Persistence.Database.Entity.Setpoint", b => { b.Property("Key") @@ -222,17 +224,6 @@ namespace DD.Persistence.Database.Postgres.Migrations b.Navigation("System"); }); - - modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedValues", b => - { - b.HasOne("DD.Persistence.Database.Entity.DataScheme", "DataScheme") - .WithMany() - .HasForeignKey("DiscriminatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("DataScheme"); - }); #pragma warning restore 612, 618 } } diff --git a/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs b/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs similarity index 90% rename from DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs rename to DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs index 24a310d..c872547 100644 --- a/DD.Persistence.Database.Postgres/Migrations/20250204044050_Init.cs +++ b/DD.Persistence.Database.Postgres/Migrations/20250205114037_Init.cs @@ -30,19 +30,6 @@ namespace DD.Persistence.Database.Postgres.Migrations table.PrimaryKey("PK_change_log", x => x.Id); }); - migrationBuilder.CreateTable( - name: "data_scheme", - columns: table => new - { - DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"), - PropNames = table.Column(type: "jsonb", nullable: false, comment: "Наименования полей в порядке индексации"), - PropTypes = table.Column(type: "integer[]", nullable: false, comment: "Типы полей в порядке индексации") - }, - constraints: table => - { - table.PrimaryKey("PK_data_scheme", x => x.DiscriminatorId); - }); - migrationBuilder.CreateTable( name: "data_source_system", columns: table => new @@ -70,6 +57,20 @@ namespace DD.Persistence.Database.Postgres.Migrations table.PrimaryKey("PK_parameter_data", x => new { x.DiscriminatorId, x.ParameterId, x.Timestamp }); }); + migrationBuilder.CreateTable( + name: "scheme_property", + columns: table => new + { + DiscriminatorId = table.Column(type: "uuid", nullable: false, comment: "Идентификатор схемы данных"), + Index = table.Column(type: "integer", nullable: false, comment: "Индекс поля"), + PropertyName = table.Column(type: "text", nullable: false, comment: "Наименования индексируемого поля"), + PropertyKind = table.Column(type: "smallint", nullable: false, comment: "Тип индексируемого поля") + }, + constraints: table => + { + table.PrimaryKey("PK_scheme_property", x => new { x.DiscriminatorId, x.Index }); + }); + migrationBuilder.CreateTable( name: "setpoint", columns: table => new @@ -95,12 +96,6 @@ namespace DD.Persistence.Database.Postgres.Migrations constraints: table => { table.PrimaryKey("PK_timestamped_values", x => new { x.DiscriminatorId, x.Timestamp }); - table.ForeignKey( - name: "FK_timestamped_values_data_scheme_DiscriminatorId", - column: x => x.DiscriminatorId, - principalTable: "data_scheme", - principalColumn: "DiscriminatorId", - onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( @@ -140,6 +135,9 @@ namespace DD.Persistence.Database.Postgres.Migrations migrationBuilder.DropTable( name: "parameter_data"); + migrationBuilder.DropTable( + name: "scheme_property"); + migrationBuilder.DropTable( name: "setpoint"); @@ -151,9 +149,6 @@ namespace DD.Persistence.Database.Postgres.Migrations migrationBuilder.DropTable( name: "data_source_system"); - - migrationBuilder.DropTable( - name: "data_scheme"); } } } diff --git a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs index ca319a5..e2b0921 100644 --- a/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs +++ b/DD.Persistence.Database.Postgres/Migrations/PersistencePostgresContextModelSnapshot.cs @@ -64,28 +64,6 @@ namespace DD.Persistence.Database.Postgres.Migrations b.ToTable("change_log"); }); - modelBuilder.Entity("DD.Persistence.Database.Entity.DataScheme", b => - { - b.Property("DiscriminatorId") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasComment("Идентификатор схемы данных"); - - b.Property("PropNames") - .IsRequired() - .HasColumnType("jsonb") - .HasComment("Наименования полей в порядке индексации"); - - b.PrimitiveCollection("PropTypes") - .IsRequired() - .HasColumnType("integer[]") - .HasComment("Типы полей в порядке индексации"); - - b.HasKey("DiscriminatorId"); - - b.ToTable("data_scheme"); - }); - modelBuilder.Entity("DD.Persistence.Database.Entity.DataSourceSystem", b => { b.Property("SystemId") @@ -131,6 +109,30 @@ namespace DD.Persistence.Database.Postgres.Migrations b.ToTable("parameter_data"); }); + modelBuilder.Entity("DD.Persistence.Database.Entity.SchemeProperty", b => + { + b.Property("DiscriminatorId") + .HasColumnType("uuid") + .HasComment("Идентификатор схемы данных"); + + b.Property("Index") + .HasColumnType("integer") + .HasComment("Индекс поля"); + + b.Property("PropertyKind") + .HasColumnType("smallint") + .HasComment("Тип индексируемого поля"); + + b.Property("PropertyName") + .IsRequired() + .HasColumnType("text") + .HasComment("Наименования индексируемого поля"); + + b.HasKey("DiscriminatorId", "Index"); + + b.ToTable("scheme_property"); + }); + modelBuilder.Entity("DD.Persistence.Database.Entity.Setpoint", b => { b.Property("Key") @@ -219,17 +221,6 @@ namespace DD.Persistence.Database.Postgres.Migrations b.Navigation("System"); }); - - modelBuilder.Entity("DD.Persistence.Database.Entity.TimestampedValues", b => - { - b.HasOne("DD.Persistence.Database.Entity.DataScheme", "DataScheme") - .WithMany() - .HasForeignKey("DiscriminatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("DataScheme"); - }); #pragma warning restore 612, 618 } } diff --git a/DD.Persistence.Database/DependencyInjection.cs b/DD.Persistence.Database/DependencyInjection.cs index c04d9e5..ca140d8 100644 --- a/DD.Persistence.Database/DependencyInjection.cs +++ b/DD.Persistence.Database/DependencyInjection.cs @@ -2,6 +2,7 @@ using DD.Persistence.Database.Postgres.Repositories; using DD.Persistence.Database.Postgres.RepositoriesCached; using DD.Persistence.Database.Repositories; +using DD.Persistence.Database.RepositoriesCached; using DD.Persistence.Models; using DD.Persistence.Repositories; using Mapster; @@ -24,6 +25,12 @@ public static class DependencyInjection Value = src.Value, Id = src.Id }); + + TypeAdapterConfig, SchemeProperty>.NewConfig() + .Map(dest => dest.DiscriminatorId, src => src.Key) + .Map(dest => dest.Index, src => src.Value.Index) + .Map(dest => dest.PropertyKind, src => src.Value.PropertyKind) + .Map(dest => dest.PropertyName, src => src.Value.PropertyName); } public static IServiceCollection AddInfrastructure(this IServiceCollection services) @@ -40,7 +47,7 @@ public static class DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); return services; } diff --git a/DD.Persistence.Database/Entity/DataScheme.cs b/DD.Persistence.Database/Entity/SchemeProperty.cs similarity index 71% rename from DD.Persistence.Database/Entity/DataScheme.cs rename to DD.Persistence.Database/Entity/SchemeProperty.cs index 3ce46a2..6ef5bdb 100644 --- a/DD.Persistence.Database/Entity/DataScheme.cs +++ b/DD.Persistence.Database/Entity/SchemeProperty.cs @@ -1,12 +1,13 @@ using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json; namespace DD.Persistence.Database.Entity; -[Table("prop_scheme")] +[Table("scheme_property")] [PrimaryKey(nameof(DiscriminatorId), nameof(Index))] -public class PropScheme +public class SchemeProperty { [Comment("Идентификатор схемы данных")] public Guid DiscriminatorId { get; set; } @@ -15,8 +16,8 @@ public class PropScheme public int Index { get; set; } [Comment("Наименования индексируемого поля")] - public required string PropName { get; set; } + public required string PropertyName { get; set; } [Comment("Тип индексируемого поля")] - public required JsonValueKind PropKind { get; set; } + public required JsonValueKind PropertyKind { get; set; } } diff --git a/DD.Persistence.Database/Entity/TimestampedValues.cs b/DD.Persistence.Database/Entity/TimestampedValues.cs index a2835f7..d28e1cf 100644 --- a/DD.Persistence.Database/Entity/TimestampedValues.cs +++ b/DD.Persistence.Database/Entity/TimestampedValues.cs @@ -17,7 +17,4 @@ public class TimestampedValues : ITimestampedItem [Comment("Данные"), Column(TypeName = "jsonb")] public required object[] Values { get; set; } - - [Required, ForeignKey(nameof(DiscriminatorId)), Comment("Идентификаторы")] - public virtual DataScheme? DataScheme { get; set; } } diff --git a/DD.Persistence.Database/PersistenceDbContext.cs b/DD.Persistence.Database/PersistenceDbContext.cs index fbbc057..4b0a874 100644 --- a/DD.Persistence.Database/PersistenceDbContext.cs +++ b/DD.Persistence.Database/PersistenceDbContext.cs @@ -10,7 +10,7 @@ public class PersistenceDbContext : DbContext { public DbSet Setpoint => Set(); - public DbSet DataSchemes => Set(); + public DbSet SchemeProperty => Set(); public DbSet TimestampedValues => Set(); @@ -30,10 +30,6 @@ public class PersistenceDbContext : DbContext protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.Entity() - .Property(e => e.PropNames) - .HasJsonConversion(); - modelBuilder.Entity() .Property(e => e.Values) .HasJsonConversion(); diff --git a/DD.Persistence.Database/Repositories/DataSchemeRepository.cs b/DD.Persistence.Database/Repositories/DataSchemeRepository.cs deleted file mode 100644 index ba5ccd7..0000000 --- a/DD.Persistence.Database/Repositories/DataSchemeRepository.cs +++ /dev/null @@ -1,34 +0,0 @@ -using DD.Persistence.Database.Entity; -using DD.Persistence.Models; -using DD.Persistence.Repositories; -using Mapster; -using Microsoft.EntityFrameworkCore; - -namespace DD.Persistence.Database.Postgres.Repositories; -public class DataSchemeRepository : IDataSchemeRepository -{ - protected DbContext db; - public DataSchemeRepository(DbContext db) - { - this.db = db; - } - protected virtual IQueryable GetQueryReadOnly() => db.Set(); - - public virtual async Task Add(DataSchemeDto dataSourceSystemDto, CancellationToken token) - { - var entity = dataSourceSystemDto.Adapt(); - - await db.Set().AddAsync(entity, token); - await db.SaveChangesAsync(token); - } - - public virtual async Task Get(Guid dataSchemeId, CancellationToken token) - { - var query = GetQueryReadOnly() - .Where(e => e.DiscriminatorId == dataSchemeId); - var entity = await query.ToArrayAsync(); - var dto = entity.Select(e => e.Adapt()).FirstOrDefault(); - - return dto; - } -} diff --git a/DD.Persistence.Database/Repositories/SchemePropertyRepository.cs b/DD.Persistence.Database/Repositories/SchemePropertyRepository.cs new file mode 100644 index 0000000..26bb8aa --- /dev/null +++ b/DD.Persistence.Database/Repositories/SchemePropertyRepository.cs @@ -0,0 +1,43 @@ +using DD.Persistence.Database.Entity; +using DD.Persistence.Models; +using DD.Persistence.Repositories; +using Mapster; +using Microsoft.EntityFrameworkCore; + +namespace DD.Persistence.Database.Repositories; +public class SchemePropertyRepository : ISchemePropertyRepository +{ + protected DbContext db; + public SchemePropertyRepository(DbContext db) + { + this.db = db; + } + protected virtual IQueryable GetQueryReadOnly() => db.Set(); + + public virtual async Task AddRange(DataSchemeDto dataSchemeDto, CancellationToken token) + { + var entities = dataSchemeDto.Select(e => + KeyValuePair.Create(dataSchemeDto.DiscriminatorId, e) + .Adapt() + ); + + await db.Set().AddRangeAsync(entities, token); + await db.SaveChangesAsync(token); + } + + public virtual async Task Get(Guid dataSchemeId, CancellationToken token) + { + var query = GetQueryReadOnly() + .Where(e => e.DiscriminatorId == dataSchemeId); + var entities = await query.ToArrayAsync(token); + + DataSchemeDto? result = null; + if (entities.Length != 0) + { + var properties = entities.Select(e => e.Adapt()).ToArray(); + result = new DataSchemeDto(dataSchemeId, properties); + } + + return result; + } +} diff --git a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs index 1239b4a..5f3f60e 100644 --- a/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs +++ b/DD.Persistence.Database/Repositories/TimestampedValuesRepository.cs @@ -14,8 +14,7 @@ public class TimestampedValuesRepository : ITimestampedValuesRepository this.db = db; } - protected virtual IQueryable GetQueryReadOnly() => this.db.Set() - .Include(e => e.DataScheme); + protected virtual IQueryable GetQueryReadOnly() => this.db.Set(); public async virtual Task AddRange(Guid discriminatorId, IEnumerable dtos, CancellationToken token) { diff --git a/DD.Persistence.Database/RepositoriesCached/DataSchemeCachedRepository.cs b/DD.Persistence.Database/RepositoriesCached/SchemePropertyCachedRepository.cs similarity index 57% rename from DD.Persistence.Database/RepositoriesCached/DataSchemeCachedRepository.cs rename to DD.Persistence.Database/RepositoriesCached/SchemePropertyCachedRepository.cs index f4cec62..64d9c01 100644 --- a/DD.Persistence.Database/RepositoriesCached/DataSchemeCachedRepository.cs +++ b/DD.Persistence.Database/RepositoriesCached/SchemePropertyCachedRepository.cs @@ -1,21 +1,21 @@ using DD.Persistence.Models; -using DD.Persistence.Database.Postgres.Repositories; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; +using DD.Persistence.Database.Repositories; -namespace DD.Persistence.Database.Postgres.RepositoriesCached; -public class DataSchemeCachedRepository : DataSchemeRepository +namespace DD.Persistence.Database.RepositoriesCached; +public class SchemePropertyCachedRepository : SchemePropertyRepository { private readonly IMemoryCache memoryCache; - public DataSchemeCachedRepository(DbContext db, IMemoryCache memoryCache) : base(db) + public SchemePropertyCachedRepository(DbContext db, IMemoryCache memoryCache) : base(db) { this.memoryCache = memoryCache; } - public override async Task Add(DataSchemeDto dataSourceSystemDto, CancellationToken token) + public override async Task AddRange(DataSchemeDto dataSourceSystemDto, CancellationToken token) { - await base.Add(dataSourceSystemDto, token); + await base.AddRange(dataSourceSystemDto, token); memoryCache.Set(dataSourceSystemDto.DiscriminatorId, dataSourceSystemDto); } diff --git a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs index 526b372..9bb1d58 100644 --- a/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs +++ b/DD.Persistence.IntegrationTests/Controllers/TimestampedValuesControllerTest.cs @@ -406,8 +406,12 @@ public class TimestampedValuesControllerTest : BaseIntegrationTest private void Cleanup() { + foreach (var item in discriminatorIds) + { + memoryCache.Remove(item); + } discriminatorIds = []; dbContext.CleanupDbSet(); - dbContext.CleanupDbSet(); + dbContext.CleanupDbSet(); } } diff --git a/DD.Persistence.Models/DataSchemeDto.cs b/DD.Persistence.Models/DataSchemeDto.cs index 7f238aa..d20ffaa 100644 --- a/DD.Persistence.Models/DataSchemeDto.cs +++ b/DD.Persistence.Models/DataSchemeDto.cs @@ -1,9 +1,11 @@ -namespace DD.Persistence.Models; +using System.Collections; + +namespace DD.Persistence.Models; /// /// Схема для набора данных /// -public class DataSchemeDto +public class DataSchemeDto : IEnumerable, IEquatable> { /// /// Дискриминатор @@ -11,12 +13,30 @@ public class DataSchemeDto public Guid DiscriminatorId { get; set; } /// - /// Наименования полей + /// Поля /// - public string[] PropNames { get; set; } = []; + private IEnumerable Properties { get; } = []; - /// - /// Типы полей - /// - public PropTypeEnum[] PropTypes { get; set; } = []; + /// + public DataSchemeDto(Guid discriminatorId, SchemePropertyDto[] Properties) + { + DiscriminatorId = discriminatorId; + this.Properties = Properties; + } + + /// + public IEnumerator GetEnumerator() + => Properties.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + public bool Equals(IEnumerable? otherProperties) + { + //if (otherProperties is null) + // return false; + + return Properties.SequenceEqual(otherProperties); + } } diff --git a/DD.Persistence.Models/Enumerations/PropTypeEnum.cs b/DD.Persistence.Models/Enumerations/PropTypeEnum.cs deleted file mode 100644 index 5379929..0000000 --- a/DD.Persistence.Models/Enumerations/PropTypeEnum.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace DD.Persistence.Models; - -/// -/// Типы для набора данных -/// -public enum PropTypeEnum -{ - /// - String = 0, - /// - Double = 1, - /// - DateTime = 2 -} diff --git a/DD.Persistence.Models/SchemePropertyDto.cs b/DD.Persistence.Models/SchemePropertyDto.cs new file mode 100644 index 0000000..0c34ba7 --- /dev/null +++ b/DD.Persistence.Models/SchemePropertyDto.cs @@ -0,0 +1,30 @@ +using System.Text.Json; + +namespace DD.Persistence.Models; + +/// +/// Индексируемого поле из схемы для набора данных +/// +public class SchemePropertyDto : IEquatable +{ + /// + /// Индекс поля + /// + public required int Index { get; set; } + + /// + /// Наименование индексируемого поля + /// + public required string PropertyName { get; set; } + + /// + /// Тип индексируемого поля + /// + public required JsonValueKind PropertyKind { get; set; } + + /// + public bool Equals(SchemePropertyDto? other) + { + return Index == other?.Index && PropertyName == other?.PropertyName && PropertyKind == other?.PropertyKind; + } +} diff --git a/DD.Persistence.Test/TimestampedValuesServiceShould.cs b/DD.Persistence.Test/TimestampedValuesServiceShould.cs index 0acb6de..ad26d14 100644 --- a/DD.Persistence.Test/TimestampedValuesServiceShould.cs +++ b/DD.Persistence.Test/TimestampedValuesServiceShould.cs @@ -7,7 +7,7 @@ namespace DD.Persistence.Repository.Test; public class TimestampedValuesServiceShould { private readonly ITimestampedValuesRepository timestampedValuesRepository = Substitute.For(); - private readonly IDataSchemeRepository dataSchemeRepository = Substitute.For(); + private readonly ISchemePropertyRepository dataSchemeRepository = Substitute.For(); private TimestampedValuesService timestampedValuesService; public TimestampedValuesServiceShould() diff --git a/DD.Persistence/Repositories/IDataSchemeRepository.cs b/DD.Persistence/Repositories/ISchemePropertyRepository.cs similarity index 84% rename from DD.Persistence/Repositories/IDataSchemeRepository.cs rename to DD.Persistence/Repositories/ISchemePropertyRepository.cs index c14a9cf..458f5cd 100644 --- a/DD.Persistence/Repositories/IDataSchemeRepository.cs +++ b/DD.Persistence/Repositories/ISchemePropertyRepository.cs @@ -5,7 +5,7 @@ namespace DD.Persistence.Repositories; /// /// Репозиторий для работы со схемами наборов данных /// -public interface IDataSchemeRepository +public interface ISchemePropertyRepository { /// /// Добавить схему @@ -13,7 +13,7 @@ public interface IDataSchemeRepository /// /// /// - Task Add(DataSchemeDto dataSourceSystemDto, CancellationToken token); + Task AddRange(DataSchemeDto dataSourceSystemDto, CancellationToken token); /// /// Вычитать схему diff --git a/DD.Persistence/Services/TimestampedValuesService.cs b/DD.Persistence/Services/TimestampedValuesService.cs index 264fdc5..5e6f9ed 100644 --- a/DD.Persistence/Services/TimestampedValuesService.cs +++ b/DD.Persistence/Services/TimestampedValuesService.cs @@ -10,10 +10,10 @@ namespace DD.Persistence.Services; public class TimestampedValuesService : ITimestampedValuesService { private readonly ITimestampedValuesRepository timestampedValuesRepository; - private readonly IDataSchemeRepository dataSchemeRepository; + private readonly ISchemePropertyRepository dataSchemeRepository; /// - public TimestampedValuesService(ITimestampedValuesRepository timestampedValuesRepository, IDataSchemeRepository relatedDataRepository) + public TimestampedValuesService(ITimestampedValuesRepository timestampedValuesRepository, ISchemePropertyRepository relatedDataRepository) { this.timestampedValuesRepository = timestampedValuesRepository; this.dataSchemeRepository = relatedDataRepository; @@ -38,7 +38,7 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.Get(discriminatorIds, geTimestamp, columnNames, skip, take, token); - var dtos = await Materialize(result, token); + var dtos = await BindingToDataScheme(result, token); if (!columnNames.IsNullOrEmpty()) { @@ -53,9 +53,9 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.GetFirst(discriminatorId, takeCount, token); - var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) } + var resultBeforeBinding = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); - var dtos = await Materialize(resultToMaterialize, token); + var dtos = await BindingToDataScheme(resultBeforeBinding, token); return dtos; } @@ -65,9 +65,9 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.GetLast(discriminatorId, takeCount, token); - var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) } + var resultBeforeBinding = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); - var dtos = await Materialize(resultToMaterialize, token); + var dtos = await BindingToDataScheme(resultBeforeBinding, token); return dtos; } @@ -82,9 +82,9 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.GetResampledData(discriminatorId, beginTimestamp, intervalSec, approxPointsCount, token); - var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) } + var resultBeforeBinding = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); - var dtos = await Materialize(resultToMaterialize, token); + var dtos = await BindingToDataScheme(resultBeforeBinding, token); return dtos; } @@ -94,9 +94,9 @@ public class TimestampedValuesService : ITimestampedValuesService { var result = await timestampedValuesRepository.GetGtDate(discriminatorId, beginTimestamp, token); - var resultToMaterialize = new[] { KeyValuePair.Create(discriminatorId, result) } + var resultBeforeBinding = new[] { KeyValuePair.Create(discriminatorId, result) } .ToDictionary(); - var dtos = await Materialize(resultToMaterialize, token); + var dtos = await BindingToDataScheme(resultBeforeBinding, token); return dtos; } @@ -108,28 +108,22 @@ public class TimestampedValuesService : ITimestampedValuesService /// /// /// - private async Task> Materialize(IDictionary> queryResult, CancellationToken token) + private async Task> BindingToDataScheme(IDictionary> queryResult, CancellationToken token) { IEnumerable result = []; foreach (var keyValuePair in queryResult) { var dataScheme = await dataSchemeRepository.Get(keyValuePair.Key, token); if (dataScheme is null) - { continue; - } foreach (var tuple in keyValuePair.Value) { - var identity = dataScheme!.PropNames; - var indexedIdentity = identity - .Select((value, index) => new { index, value }); - var dto = new TimestampedValuesDto() { Timestamp = tuple.Timestamp.ToUniversalTime(), - Values = indexedIdentity - .ToDictionary(x => x.value, x => tuple.Values[x.index]) + Values = dataScheme + .ToDictionary(k => k.PropertyName, v => tuple.Values[v.Index]) }; result = result.Append(dto); @@ -149,61 +143,29 @@ public class TimestampedValuesService : ITimestampedValuesService /// Некорректный набор наименований полей private async Task CreateDataSchemeIfNotExist(Guid discriminatorId, TimestampedValuesDto dto, CancellationToken token) { - var propNames = dto.Values.Keys.ToArray(); - var propTypes = GetPropTypes(dto); + var valuesList = dto.Values.ToList(); + var properties = valuesList.ToList().Select(e => new SchemePropertyDto() { + Index = valuesList.IndexOf(e), + PropertyName = e.Key, + PropertyKind = ((JsonElement) e.Value).ValueKind + }).ToArray(); var dataScheme = await dataSchemeRepository.Get(discriminatorId, token); if (dataScheme is null) { - dataScheme = new DataSchemeDto() - { - DiscriminatorId = discriminatorId, - PropNames = propNames, - PropTypes = propTypes - }; - await dataSchemeRepository.Add(dataScheme, token); + dataScheme = new DataSchemeDto(discriminatorId, properties); + await dataSchemeRepository.AddRange(dataScheme, token); return; } - if (!dataScheme.PropNames.SequenceEqual(propNames)) + if (!dataScheme.Equals(properties)) { - var expectedFieldNames = string.Join(", ", dataScheme.PropNames); - var actualFieldNames = string.Join(", ", propNames); throw new InvalidOperationException($"Для системы {discriminatorId.ToString()} " + - $"характерен набор данных: [{expectedFieldNames}], однако был передан набор: [{actualFieldNames}]"); + $"был передан нехарактерный набор данных"); } } - /// - /// Получить типы для набора данных в соответствии с индексацией - /// - /// - /// - /// - private PropTypeEnum[] GetPropTypes(TimestampedValuesDto dto) - { - var types = dto.Values.Select(e => - { - var objectKind = ((JsonElement) e.Value).ValueKind; - var valueString = e.Value.ToString(); - - if (valueString is null) - throw new ArgumentNullException("Переданный набор данных содержит null, в следствии чего не удаётся определить типы полей"); - - if (DateTimeOffset.TryParse(valueString, out _)) - return PropTypeEnum.DateTime; - - var doubleString = valueString.Replace('.', ','); - if (double.TryParse(doubleString, out _)) - return PropTypeEnum.Double; - - return PropTypeEnum.String; - }); - - return types.ToArray(); - } - /// /// Отсеить лишние поля в соответствии с заданным фильтром /// From 7d973ba85926e163c76cda323e83701826f07dfa Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Thu, 6 Feb 2025 09:31:10 +0500 Subject: [PATCH 11/13] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20#3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DependencyInjection.cs | 1 + .../TimestampedValuesCachedRepository.cs | 103 ------------------ 2 files changed, 1 insertion(+), 103 deletions(-) delete mode 100644 DD.Persistence.Database/RepositoriesCached/TimestampedValuesCachedRepository.cs diff --git a/DD.Persistence.Database/DependencyInjection.cs b/DD.Persistence.Database/DependencyInjection.cs index ca140d8..a9291e2 100644 --- a/DD.Persistence.Database/DependencyInjection.cs +++ b/DD.Persistence.Database/DependencyInjection.cs @@ -13,6 +13,7 @@ namespace DD.Persistence.Database; public static class DependencyInjection { + // ToDo: перенести в другой файл public static void MapsterSetup() { TypeAdapterConfig.GlobalSettings.Default.Config diff --git a/DD.Persistence.Database/RepositoriesCached/TimestampedValuesCachedRepository.cs b/DD.Persistence.Database/RepositoriesCached/TimestampedValuesCachedRepository.cs deleted file mode 100644 index 2073126..0000000 --- a/DD.Persistence.Database/RepositoriesCached/TimestampedValuesCachedRepository.cs +++ /dev/null @@ -1,103 +0,0 @@ -//using DD.Persistence.Models; -//using DD.Persistence.Models.Common; -//using DD.Persistence.Repositories; -//using Microsoft.EntityFrameworkCore; - -//namespace DD.Persistence.Database.Postgres.Repositories; - -//public class TimestampedValuesCachedRepository : TimestampedValuesRepository -//{ -// public static TimestampedValuesDto? FirstByDate { get; private set; } -// public static CyclicArray LastData { get; } = new CyclicArray(CacheItemsCount); - -// private const int CacheItemsCount = 3600; - -// public TimestampedValuesCachedRepository(DbContext db, IDataSourceSystemRepository relatedDataRepository) : base(db, relatedDataRepository) -// { -// //Task.Run(async () => -// //{ -// // var firstDateItem = await base.GetFirst(CancellationToken.None); -// // if (firstDateItem == null) -// // { -// // return; -// // } - -// // FirstByDate = firstDateItem; - -// // var dtos = await base.GetLast(CacheItemsCount, CancellationToken.None); -// // dtos = dtos.OrderBy(d => d.Timestamp); -// // LastData.AddRange(dtos); -// //}).Wait(); -// } - -// public override async Task> GetGtDate(Guid discriminatorId, DateTimeOffset dateBegin, CancellationToken token) -// { - -// if (LastData.Count == 0 || LastData[0].Timestamp > dateBegin) -// { -// var dtos = await base.GetGtDate(discriminatorId, dateBegin, token); -// return dtos; -// } - -// var items = LastData -// .Where(i => i.Timestamp >= dateBegin); - -// return items; -// } - -// public override async Task AddRange(Guid discriminatorId, IEnumerable dtos, CancellationToken token) -// { -// var result = await base.AddRange(discriminatorId, dtos, token); -// if (result > 0) -// { - -// dtos = dtos.OrderBy(x => x.Timestamp); - -// FirstByDate = dtos.First(); -// LastData.AddRange(dtos); -// } - -// return result; -// } - -// public override async Task GetDatesRange(Guid discriminatorId, CancellationToken token) -// { -// if (FirstByDate == null) -// return null; - -// return await Task.Run(() => -// { -// return new DatesRangeDto -// { -// From = FirstByDate.Timestamp, -// To = LastData[^1].Timestamp -// }; -// }); -// } - -// public override async Task> GetResampledData( -// Guid discriminatorId, -// DateTimeOffset dateBegin, -// double intervalSec = 600d, -// int approxPointsCount = 1024, -// CancellationToken token = default) -// { -// var dtos = LastData.Where(i => i.Timestamp >= dateBegin); -// if (LastData.Count == 0 || LastData[0].Timestamp > dateBegin) -// { -// dtos = await base.GetGtDate(discriminatorId, dateBegin, token); -// } - -// var dateEnd = dateBegin.AddSeconds(intervalSec); -// dtos = dtos -// .Where(i => i.Timestamp <= dateEnd); - -// var ratio = dtos.Count() / approxPointsCount; -// if (ratio > 1) -// dtos = dtos -// .Where((_, index) => index % ratio == 0); - -// return dtos; -// } -//} - From c5da82c2105f4372739a3dd3e8b689eaef5c09ac Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Thu, 6 Feb 2025 12:39:40 +0500 Subject: [PATCH 12/13] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20#4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.Models/DataSchemeDto.cs | 6 +++--- .../TimestampedValuesServiceShould.cs | 16 ++++++++++++---- .../Services/TimestampedValuesService.cs | 17 +++++++++-------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/DD.Persistence.Models/DataSchemeDto.cs b/DD.Persistence.Models/DataSchemeDto.cs index d20ffaa..2b28176 100644 --- a/DD.Persistence.Models/DataSchemeDto.cs +++ b/DD.Persistence.Models/DataSchemeDto.cs @@ -18,7 +18,7 @@ public class DataSchemeDto : IEnumerable, IEquatable Properties { get; } = []; /// - public DataSchemeDto(Guid discriminatorId, SchemePropertyDto[] Properties) + public DataSchemeDto(Guid discriminatorId, IEnumerable Properties) { DiscriminatorId = discriminatorId; this.Properties = Properties; @@ -34,8 +34,8 @@ public class DataSchemeDto : IEnumerable, IEquatable public bool Equals(IEnumerable? otherProperties) { - //if (otherProperties is null) - // return false; + if (otherProperties is null) + return false; return Properties.SequenceEqual(otherProperties); } diff --git a/DD.Persistence.Test/TimestampedValuesServiceShould.cs b/DD.Persistence.Test/TimestampedValuesServiceShould.cs index ad26d14..0fe7769 100644 --- a/DD.Persistence.Test/TimestampedValuesServiceShould.cs +++ b/DD.Persistence.Test/TimestampedValuesServiceShould.cs @@ -2,6 +2,7 @@ using DD.Persistence.Repositories; using DD.Persistence.Services; using NSubstitute; +using System.Text.Json; namespace DD.Persistence.Repository.Test; public class TimestampedValuesServiceShould @@ -45,10 +46,10 @@ public class TimestampedValuesServiceShould { var values = new Dictionary() { - { "A", i }, - { "B", i * 1.1 }, - { "C", $"Any{i}" }, - { "D", DateTimeOffset.Now }, + { "A", GetJsonFromObject(i) }, + { "B", GetJsonFromObject(i * 1.1) }, + { "C", GetJsonFromObject($"Any{i}") }, + { "D", GetJsonFromObject(DateTimeOffset.Now) } }; yield return new TimestampedValuesDto() @@ -58,4 +59,11 @@ public class TimestampedValuesServiceShould }; } } + + private static JsonElement GetJsonFromObject(object value) + { + var jsonString = JsonSerializer.Serialize(value); + var doc = JsonDocument.Parse(jsonString); + return doc.RootElement; + } } diff --git a/DD.Persistence/Services/TimestampedValuesService.cs b/DD.Persistence/Services/TimestampedValuesService.cs index 5e6f9ed..cef700f 100644 --- a/DD.Persistence/Services/TimestampedValuesService.cs +++ b/DD.Persistence/Services/TimestampedValuesService.cs @@ -117,13 +117,13 @@ public class TimestampedValuesService : ITimestampedValuesService if (dataScheme is null) continue; - foreach (var tuple in keyValuePair.Value) + foreach (var (Timestamp, Values) in keyValuePair.Value) { var dto = new TimestampedValuesDto() { - Timestamp = tuple.Timestamp.ToUniversalTime(), + Timestamp = Timestamp.ToUniversalTime(), Values = dataScheme - .ToDictionary(k => k.PropertyName, v => tuple.Values[v.Index]) + .ToDictionary(k => k.PropertyName, v => Values[v.Index]) }; result = result.Append(dto); @@ -144,11 +144,12 @@ public class TimestampedValuesService : ITimestampedValuesService private async Task CreateDataSchemeIfNotExist(Guid discriminatorId, TimestampedValuesDto dto, CancellationToken token) { var valuesList = dto.Values.ToList(); - var properties = valuesList.ToList().Select(e => new SchemePropertyDto() { - Index = valuesList.IndexOf(e), + var properties = valuesList.Select((e, index) => new SchemePropertyDto() + { + Index = index, PropertyName = e.Key, - PropertyKind = ((JsonElement) e.Value).ValueKind - }).ToArray(); + PropertyKind = ((JsonElement)e.Value).ValueKind + }); var dataScheme = await dataSchemeRepository.Get(discriminatorId, token); if (dataScheme is null) @@ -172,7 +173,7 @@ public class TimestampedValuesService : ITimestampedValuesService /// /// Поля, которые необходимо оставить /// - private IEnumerable ReduceSetColumnsByNames(IEnumerable dtos, IEnumerable fieldNames) + private static IEnumerable ReduceSetColumnsByNames(IEnumerable dtos, IEnumerable fieldNames) { var result = dtos.Select(dto => { From aad8c575114b6e0efbc69395b3129abcca928259 Mon Sep 17 00:00:00 2001 From: Roman Efremov Date: Thu, 6 Feb 2025 15:50:04 +0500 Subject: [PATCH 13/13] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=81=D0=BB=D0=BE=D0=BC=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=82=D0=B5=D1=81=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DD.Persistence.Test/TimestampedValuesServiceShould.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DD.Persistence.Test/TimestampedValuesServiceShould.cs b/DD.Persistence.Test/TimestampedValuesServiceShould.cs index 165d4e0..cb62521 100644 --- a/DD.Persistence.Test/TimestampedValuesServiceShould.cs +++ b/DD.Persistence.Test/TimestampedValuesServiceShould.cs @@ -7,7 +7,7 @@ namespace DD.Persistence.Test; public class TimestampedValuesServiceShould { private readonly ITimestampedValuesRepository timestampedValuesRepository = Substitute.For(); - private readonly IDataSchemeRepository dataSchemeRepository = Substitute.For(); + private readonly ISchemePropertyRepository dataSchemeRepository = Substitute.For(); private readonly TimestampedValuesService timestampedValuesService; public TimestampedValuesServiceShould()