138 lines
6.5 KiB
C#
138 lines
6.5 KiB
C#
|
using Ardalis.Specification;
|
|||
|
using DD.Persistence.Database.Entity;
|
|||
|
using DD.Persistence.Database.EntityAbstractions;
|
|||
|
using DD.Persistence.Database.Postgres.Extensions;
|
|||
|
using DD.Persistence.Database.Specifications.ValuesItem;
|
|||
|
using DD.Persistence.Filter.Models.Abstractions;
|
|||
|
using DD.Persistence.Filter.Models.Enumerations;
|
|||
|
using DD.Persistence.Filter.Visitors;
|
|||
|
using DD.Persistence.Models;
|
|||
|
|
|||
|
namespace DD.Persistence.Database.Postgres.Helpers;
|
|||
|
public static class FilterBuilder
|
|||
|
{
|
|||
|
public static ISpecification<TEntity>? BuildFilter<TEntity>(this DataScheme dataScheme, TNode root)
|
|||
|
where TEntity : IValuesItem
|
|||
|
{
|
|||
|
var result = dataScheme.BuildSpecificationByNextNode<TEntity>(root);
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
private static ISpecification<TEntity>? BuildSpecificationByNextNode<TEntity>(this DataScheme dataScheme, TNode node)
|
|||
|
where TEntity : IValuesItem
|
|||
|
{
|
|||
|
var propIndexMap = dataScheme.PropNames
|
|||
|
.Select((name, index) => new { name, index })
|
|||
|
.ToDictionary(x => x.name, x => x.index);
|
|||
|
|
|||
|
var visitor = new NodeVisitor<ISpecification<TEntity>?>(
|
|||
|
v =>
|
|||
|
{
|
|||
|
var leftSpecification = dataScheme.BuildSpecificationByNextNode<TEntity>(v.Left);
|
|||
|
var rigthSpecification = dataScheme.BuildSpecificationByNextNode<TEntity>(v.Rigth);
|
|||
|
if (leftSpecification is null)
|
|||
|
return rigthSpecification;
|
|||
|
if (rigthSpecification is null)
|
|||
|
return leftSpecification;
|
|||
|
|
|||
|
ISpecification<TEntity>? result = null;
|
|||
|
switch (v.Operation)
|
|||
|
{
|
|||
|
case OperationEnum.And:
|
|||
|
result = leftSpecification.And(rigthSpecification);
|
|||
|
break;
|
|||
|
case OperationEnum.Or:
|
|||
|
result = leftSpecification.Or(rigthSpecification);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
},
|
|||
|
t =>
|
|||
|
{
|
|||
|
int keyIndex;
|
|||
|
if (!propIndexMap.TryGetValue(t.PropName, out keyIndex))
|
|||
|
throw new ArgumentException($"Свойство {t.PropName} не найдено в схеме данных");
|
|||
|
var type = dataScheme.PropTypes[keyIndex];
|
|||
|
|
|||
|
ISpecification<TEntity>? result = null;
|
|||
|
switch (type)
|
|||
|
{
|
|||
|
case PropTypeEnum.String:
|
|||
|
var stringValue = Convert.ToString(t.Value);
|
|||
|
switch (t.Operation)
|
|||
|
{
|
|||
|
case OperationEnum.Equal:
|
|||
|
result = new ValueEqaulSpecification<TEntity>(keyIndex, stringValue);
|
|||
|
break;
|
|||
|
case OperationEnum.NotEqual:
|
|||
|
result = new ValueNotEqaulSpecification<TEntity>(keyIndex, stringValue);
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
case PropTypeEnum.Double:
|
|||
|
var doubleValue = Convert.ToDouble(t.Value);
|
|||
|
switch (t.Operation)
|
|||
|
// ToDo: можно схлопнуть в один Generic - метод, где TValue : struct
|
|||
|
// Но в таком случае придётся продумать аналогичное решение на уровне спецификаций
|
|||
|
{
|
|||
|
case OperationEnum.Equal:
|
|||
|
result = new ValueEqaulSpecification<TEntity>(keyIndex, doubleValue);
|
|||
|
break;
|
|||
|
case OperationEnum.NotEqual:
|
|||
|
result = new ValueNotEqaulSpecification<TEntity>(keyIndex, doubleValue);
|
|||
|
break;
|
|||
|
case OperationEnum.Greate:
|
|||
|
result = new ValueGreateSpecification<TEntity>(keyIndex, doubleValue);
|
|||
|
break;
|
|||
|
case OperationEnum.GreateOrEqual:
|
|||
|
result = new ValueGreateOrEqualSpecification<TEntity>(keyIndex, doubleValue);
|
|||
|
break;
|
|||
|
case OperationEnum.Less:
|
|||
|
result = new ValueLessSpecification<TEntity>(keyIndex, doubleValue);
|
|||
|
break;
|
|||
|
case OperationEnum.LessOrEqual:
|
|||
|
result = new ValueLessOrEqualSpecification<TEntity>(keyIndex, doubleValue);
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
case PropTypeEnum.DateTime:
|
|||
|
stringValue = Convert.ToString(t.Value);
|
|||
|
DateTimeOffset? dateTimeValue = string.IsNullOrEmpty(stringValue)
|
|||
|
? null
|
|||
|
: DateTimeOffset.Parse(stringValue);
|
|||
|
switch (t.Operation)
|
|||
|
{
|
|||
|
case OperationEnum.Equal:
|
|||
|
result = new ValueEqaulSpecification<TEntity>(keyIndex, dateTimeValue);
|
|||
|
break;
|
|||
|
case OperationEnum.NotEqual:
|
|||
|
result = new ValueNotEqaulSpecification<TEntity>(keyIndex, dateTimeValue);
|
|||
|
break;
|
|||
|
case OperationEnum.Greate:
|
|||
|
result = new ValueGreateSpecification<TEntity>(keyIndex, dateTimeValue);
|
|||
|
break;
|
|||
|
case OperationEnum.GreateOrEqual:
|
|||
|
result = new ValueGreateOrEqualSpecification<TEntity>(keyIndex, dateTimeValue);
|
|||
|
break;
|
|||
|
case OperationEnum.Less:
|
|||
|
result = new ValueLessSpecification<TEntity>(keyIndex, dateTimeValue);
|
|||
|
break;
|
|||
|
case OperationEnum.LessOrEqual:
|
|||
|
result = new ValueLessOrEqualSpecification<TEntity>(keyIndex, dateTimeValue);
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
);
|
|||
|
|
|||
|
var result = node.AcceptVisitor(visitor);
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
}
|