Merge branch 'TreeBuilder' into FilterBuilder
This commit is contained in:
commit
87264fd8db
107
DD.Persistence.Test/TreeBuilderShould.cs
Normal file
107
DD.Persistence.Test/TreeBuilderShould.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
22
DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs
Normal file
22
DD.Persistence/Filter/Models/Abstractions/INodeVisitor.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace DD.Persistence.Filter.Models.Abstractions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Посетитель бинарного дерева
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TVisitResult"></typeparam>
|
||||||
|
public interface INodeVisitor<TVisitResult>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Посетить узел
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vertex"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TVisitResult Visit(TVertex vertex);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Посетить лист
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="leaf"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TVisitResult Visit(TLeaf leaf);
|
||||||
|
}
|
28
DD.Persistence/Filter/Models/Abstractions/TNode.cs
Normal file
28
DD.Persistence/Filter/Models/Abstractions/TNode.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using DD.Persistence.Filter.Models.Enumerations;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Filter.Models.Abstractions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Абстрактная модель вершины
|
||||||
|
/// </summary>
|
||||||
|
public abstract class TNode
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TNode(OperationEnum operation)
|
||||||
|
{
|
||||||
|
Operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Логическая операция
|
||||||
|
/// </summary>
|
||||||
|
public OperationEnum Operation { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Принять посетителя
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TVisitResult"></typeparam>
|
||||||
|
/// <param name="visitor"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract TVisitResult AcceptVisitor<TVisitResult>(INodeVisitor<TVisitResult> visitor);
|
||||||
|
}
|
47
DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs
Normal file
47
DD.Persistence/Filter/Models/Enumerations/OperationEnum.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
namespace DD.Persistence.Filter.Models.Enumerations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Логические операции
|
||||||
|
/// </summary>
|
||||||
|
public enum OperationEnum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// И
|
||||||
|
/// </summary>
|
||||||
|
And = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ИЛИ
|
||||||
|
/// </summary>
|
||||||
|
Or = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// РАВНО
|
||||||
|
/// </summary>
|
||||||
|
Equal = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// НЕ РАВНО
|
||||||
|
/// </summary>
|
||||||
|
NotEqual = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// БОЛЬШЕ
|
||||||
|
/// </summary>
|
||||||
|
Greate = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// БОЛЬШЕ ЛИБО РАВНО
|
||||||
|
/// </summary>
|
||||||
|
GreateOrEqual = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// МЕНЬШЕ
|
||||||
|
/// </summary>
|
||||||
|
Less = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// МЕНЬШЕ ЛИБО РАВНО
|
||||||
|
/// </summary>
|
||||||
|
LessOrEqual = 8
|
||||||
|
}
|
33
DD.Persistence/Filter/Models/TLeaf.cs
Normal file
33
DD.Persistence/Filter/Models/TLeaf.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using DD.Persistence.Filter.Models.Abstractions;
|
||||||
|
using DD.Persistence.Filter.Models.Enumerations;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Filter.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Модель листа
|
||||||
|
/// </summary>
|
||||||
|
public class TLeaf : TNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Наименование поля
|
||||||
|
/// </summary>
|
||||||
|
public string PropName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Значение для фильтрации
|
||||||
|
/// </summary>
|
||||||
|
public object? Value { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TLeaf(OperationEnum operation, string fieldName, object? value) : base(operation)
|
||||||
|
{
|
||||||
|
PropName = fieldName;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override TVisitResult AcceptVisitor<TVisitResult>(INodeVisitor<TVisitResult> visitor)
|
||||||
|
{
|
||||||
|
return visitor.Visit(this);
|
||||||
|
}
|
||||||
|
}
|
33
DD.Persistence/Filter/Models/TVertex.cs
Normal file
33
DD.Persistence/Filter/Models/TVertex.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using DD.Persistence.Filter.Models.Abstractions;
|
||||||
|
using DD.Persistence.Filter.Models.Enumerations;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Filter.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Модель узла
|
||||||
|
/// </summary>
|
||||||
|
public class TVertex : TNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Левый потомок
|
||||||
|
/// </summary>
|
||||||
|
public TNode Left { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Правый потомок
|
||||||
|
/// </summary>
|
||||||
|
public TNode Rigth { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TVertex(OperationEnum operation, TNode left, TNode rigth) : base(operation)
|
||||||
|
{
|
||||||
|
Left = left;
|
||||||
|
Rigth = rigth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override TVisitResult AcceptVisitor<TVisitResult>(INodeVisitor<TVisitResult> visitor)
|
||||||
|
{
|
||||||
|
return visitor.Visit(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
using DD.Persistence.Filter.Models.Abstractions;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Filter.Interpreter.Abstractions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Интерпретатор для построения дерева
|
||||||
|
/// </summary>
|
||||||
|
public interface ITreeBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Построить дерево
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="treeString">Дерево в виде строки</param>
|
||||||
|
/// <returns>Корень дерева в виде вершины</returns>
|
||||||
|
TNode? Build(string treeString);
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
using DD.Persistence.Filter.Models.Enumerations;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Filter.Interpreter.Expressions.Abstract;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Интерфейс для выражений
|
||||||
|
/// </summary>
|
||||||
|
public interface IExpression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Получить логическую операцию
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public OperationEnum GetOperation();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить логическую операцию в виде строки (для регулярных выражений)
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string GetOperationString();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Реализация правила
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
public void Interpret(InterpreterContext context);
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Абстрактный класс для нетерминальных выражений
|
||||||
|
/// </summary>
|
||||||
|
public abstract class NonTerminalExpression : IExpression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Реализация правила для нетерминальных выражений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public abstract OperationEnum GetOperation();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public abstract string GetOperationString();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить из акткуального состояния строки все совпадения для текущего выражения
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerable<Match> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Выражение для "И"
|
||||||
|
/// </summary>
|
||||||
|
public class AndExpression : NonTerminalExpression
|
||||||
|
{
|
||||||
|
private const string AndString = "&&";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override OperationEnum GetOperation()
|
||||||
|
{
|
||||||
|
return OperationEnum.And;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string GetOperationString()
|
||||||
|
{
|
||||||
|
return AndString;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Выражение для "ИЛИ"
|
||||||
|
/// </summary>
|
||||||
|
public class OrExpression : NonTerminalExpression
|
||||||
|
{
|
||||||
|
private const string OrString = @"\|\|";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override OperationEnum GetOperation()
|
||||||
|
{
|
||||||
|
return OperationEnum.Or;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string GetOperationString()
|
||||||
|
{
|
||||||
|
return OrString;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Абстрактный класс для терминальных выражений
|
||||||
|
/// </summary>
|
||||||
|
public abstract class TerminalExpression : IExpression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Реализация правила для терминальных выражений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public abstract OperationEnum GetOperation();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public abstract string GetOperationString();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить из акткуального состояния строки все совпадения для текущего выражения
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerable<Match> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Выражение для "РАВНО"
|
||||||
|
/// </summary>
|
||||||
|
public class EqualExpression : TerminalExpression
|
||||||
|
{
|
||||||
|
private const string EqualString = "==";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override OperationEnum GetOperation()
|
||||||
|
{
|
||||||
|
return OperationEnum.Equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string GetOperationString()
|
||||||
|
{
|
||||||
|
return EqualString;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Выражение для "МЕНЬШЕ"
|
||||||
|
/// </summary>
|
||||||
|
public class LessExpression : TerminalExpression
|
||||||
|
{
|
||||||
|
private const string EqualString = "<";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override OperationEnum GetOperation()
|
||||||
|
{
|
||||||
|
return OperationEnum.Less;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string GetOperationString()
|
||||||
|
{
|
||||||
|
return EqualString;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Выражение для "МЕНЬШЕ ЛИБО РАВНО"
|
||||||
|
/// </summary>
|
||||||
|
public class LessOrEqualExpression : TerminalExpression
|
||||||
|
{
|
||||||
|
private const string EqualString = "<=";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override OperationEnum GetOperation()
|
||||||
|
{
|
||||||
|
return OperationEnum.LessOrEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string GetOperationString()
|
||||||
|
{
|
||||||
|
return EqualString;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Выражение для "БОЛЬШЕ"
|
||||||
|
/// </summary>
|
||||||
|
public class MoreExpression : TerminalExpression
|
||||||
|
{
|
||||||
|
private const string EqualString = ">";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override OperationEnum GetOperation()
|
||||||
|
{
|
||||||
|
return OperationEnum.Greate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string GetOperationString()
|
||||||
|
{
|
||||||
|
return EqualString;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Выражение для "БОЛЬШЕ ЛИБО РАВНО"
|
||||||
|
/// </summary>
|
||||||
|
public class MoreOrEqualExpression : TerminalExpression
|
||||||
|
{
|
||||||
|
private const string EqualString = ">=";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override OperationEnum GetOperation()
|
||||||
|
{
|
||||||
|
return OperationEnum.GreateOrEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string GetOperationString()
|
||||||
|
{
|
||||||
|
return EqualString;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Выражение для "НЕРАВНО"
|
||||||
|
/// </summary>
|
||||||
|
public class NotEqualExpression : TerminalExpression
|
||||||
|
{
|
||||||
|
private const string NotEqulString = "!=";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override OperationEnum GetOperation()
|
||||||
|
{
|
||||||
|
return OperationEnum.NotEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string GetOperationString()
|
||||||
|
{
|
||||||
|
return NotEqulString;
|
||||||
|
}
|
||||||
|
}
|
30
DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs
Normal file
30
DD.Persistence/Filter/TreeBuilder/InterpreterContext.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using DD.Persistence.Filter.Models.Abstractions;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Filter.Interpreter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Контекст интерпретатора
|
||||||
|
/// </summary>
|
||||||
|
public class InterpreterContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Корень дерева (результат интерпретации)
|
||||||
|
/// </summary>
|
||||||
|
public TNode? root { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дерево в виде строки (входной параметр)
|
||||||
|
/// </summary>
|
||||||
|
public string treeString { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Проиндексированные вершины дерева
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<int, TNode> treeNodes { get; set; } = [];
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public InterpreterContext(string theeString)
|
||||||
|
{
|
||||||
|
this.treeString = theeString;
|
||||||
|
}
|
||||||
|
}
|
52
DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs
Normal file
52
DD.Persistence/Filter/TreeBuilder/TreeBuilder.cs
Normal file
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Строитель бинарных деревьев
|
||||||
|
/// </summary>
|
||||||
|
public static class TreeBuilder
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Построить бинарное дерево логических операций сравнения из строки
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="treeString"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static TNode? BuildTree(this string treeString)
|
||||||
|
{
|
||||||
|
InterpreterContext context = new InterpreterContext(treeString);
|
||||||
|
|
||||||
|
// Порядок важен
|
||||||
|
List<IExpression> terminalExpressions = new List<IExpression>
|
||||||
|
{
|
||||||
|
new EqualExpression(),
|
||||||
|
new NotEqualExpression(),
|
||||||
|
new MoreOrEqualExpression(),
|
||||||
|
new LessOrEqualExpression(),
|
||||||
|
new MoreExpression(),
|
||||||
|
new LessExpression()
|
||||||
|
};
|
||||||
|
terminalExpressions.ForEach(e => {
|
||||||
|
e.Interpret(context);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Порядок важен
|
||||||
|
List<IExpression> nonTerminalExpressions = new List<IExpression>
|
||||||
|
{
|
||||||
|
new OrExpression(),
|
||||||
|
new AndExpression()
|
||||||
|
};
|
||||||
|
while (!string.IsNullOrEmpty(context.treeString))
|
||||||
|
{
|
||||||
|
nonTerminalExpressions.ForEach(e => {
|
||||||
|
e.Interpret(context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.root;
|
||||||
|
}
|
||||||
|
}
|
24
DD.Persistence/Filter/Visitors/NodeVisitor.cs
Normal file
24
DD.Persistence/Filter/Visitors/NodeVisitor.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using DD.Persistence.Filter.Models;
|
||||||
|
using DD.Persistence.Filter.Models.Abstractions;
|
||||||
|
|
||||||
|
namespace DD.Persistence.Filter.Visitors;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public class NodeVisitor<TVisitResult> : INodeVisitor<TVisitResult>
|
||||||
|
{
|
||||||
|
private readonly Func<TVertex, TVisitResult> _ifVertex;
|
||||||
|
private readonly Func<TLeaf, TVisitResult> _ifLeaf;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public NodeVisitor(Func<TVertex, TVisitResult> ifVertex, Func<TLeaf, TVisitResult> ifLeaf)
|
||||||
|
{
|
||||||
|
_ifVertex = ifVertex;
|
||||||
|
_ifLeaf = ifLeaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TVisitResult Visit(TVertex vertex) => _ifVertex(vertex);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TVisitResult Visit(TLeaf leaf) => _ifLeaf(leaf);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user