using Ardalis.Specification; using DD.Persistence.Database.EntityAbstractions; using DD.Persistence.Database.Postgres.Extensions; using DD.Persistence.Database.Specifications; using DD.Persistence.Database.Specifications.ValuesItem; using DD.Persistence.Filter.Models; using DD.Persistence.Filter.Models.Abstractions; using DD.Persistence.Filter.Models.Enumerations; using DD.Persistence.Filter.Visitors; using DD.Persistence.Models; using System.Text.Json; namespace DD.Persistence.Database.Postgres.Helpers; public static class FilterBuilder { public static ISpecification? BuildFilter(this DataSchemeDto dataSchemeDto, TNode root) where TEntity : IValuesItem { var result = dataSchemeDto.BuildSpecificationByNextNode(root); return result; } private static ISpecification? BuildSpecificationByNextNode(this DataSchemeDto dataSchemeDto, TNode node) where TEntity : IValuesItem { var visitor = new NodeVisitor?>( dataSchemeDto.VertexProcessing, dataSchemeDto.LeafProcessing ); var result = node.AcceptVisitor(visitor); return result; } private static ISpecification? VertexProcessing(this DataSchemeDto dataSchemeDto, TVertex vertex) where TEntity : IValuesItem { var leftSpecification = dataSchemeDto.BuildSpecificationByNextNode(vertex.Left); var rigthSpecification = dataSchemeDto.BuildSpecificationByNextNode(vertex.Rigth); if (leftSpecification is null) return rigthSpecification; if (rigthSpecification is null) return leftSpecification; ISpecification? result = null; switch (vertex.Operation) { case OperationEnum.And: result = new AndSpecification(leftSpecification, rigthSpecification); break; case OperationEnum.Or: result = new OrSpecification(leftSpecification, rigthSpecification); break; } return result; } private static ISpecification? LeafProcessing(this DataSchemeDto dataSchemeDto, TLeaf leaf) where TEntity : IValuesItem { var schemeProperty = dataSchemeDto.FirstOrDefault(e => e.PropertyName.Equals(leaf.PropName)); if (schemeProperty is null) throw new ArgumentException($"Свойство {leaf.PropName} не найдено в схеме данных"); ISpecification? result = null; switch (schemeProperty.PropertyKind) { case JsonValueKind.String: var stringValue = Convert.ToString(leaf.Value); var stringSpecifications = StringSpecifications(); result = stringSpecifications[leaf.Operation](schemeProperty.Index, stringValue); break; case JsonValueKind.Number: var doubleValue = Convert.ToDouble(leaf.Value); var doubleSpecifications = DoubleSpecifications(); result = doubleSpecifications[leaf.Operation](schemeProperty.Index, doubleValue); break; } return result; } private static Dictionary>> StringSpecifications() where TEntity : IValuesItem => new() { { OperationEnum.Equal, (int index, string? value) => new ValueEqaulSpecification(index, value) }, { OperationEnum.NotEqual, (int index, string? value) => new ValueNotEqualSpecification(index, value) }, { OperationEnum.Greate, (int index, string? value) => new ValueGreateSpecification(index, value) }, { OperationEnum.GreateOrEqual, (int index, string? value) => new ValueGreateOrEqualSpecification(index, value) }, { OperationEnum.Less, (int index, string? value) => new ValueLessSpecification(index, value) }, { OperationEnum.LessOrEqual, (int index, string? value) => new ValueLessOrEqualSpecification(index, value) } }; private static Dictionary>> DoubleSpecifications() where TEntity : IValuesItem => new() { { OperationEnum.Equal, (int index, double? value) => new ValueEqaulSpecification(index, value) }, { OperationEnum.NotEqual, (int index, double? value) => new ValueNotEqualSpecification(index, value) }, { OperationEnum.Greate, (int index, double? value) => new ValueGreateSpecification(index, value) }, { OperationEnum.GreateOrEqual, (int index, double? value) => new ValueGreateOrEqualSpecification(index, value) }, { OperationEnum.Less, (int index, double? value) => new ValueLessSpecification(index, value) }, { OperationEnum.LessOrEqual, (int index, double? value) => new ValueLessOrEqualSpecification(index, value) } }; }