persistence/DD.Persistence.Database.Postgres/Helpers/FilterBuilder.cs

138 lines
6.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}