using PoweredSoft.DynamicLinq.Helpers; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace PoweredSoft.DynamicLinq.Fluent { public class QueryBuilder { public IQueryable Query { get; set; } public Type QueryableType { get; set; } public List Parts { get; protected set; } = new List(); public QueryBuilder(IQueryable query) { Query = query; } public virtual QueryBuilder Compare(string path, ConditionOperators conditionOperators, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, bool and = true) { Parts.Add(new QueryBuilderFilter { And = and, ConditionOperator = conditionOperators, Path = path, Value = value, ConvertStrategy = convertStrategy }); return this; } public virtual QueryBuilder SubQuery(Action> subQuery, bool and = true) { // create query builder for same type. var qb = new QueryBuilder(Query); // callback. subQuery(qb); // create a query part. var part = new QueryBuilderFilter(); part.And = and; part.Parts = qb.Parts; Parts.Add(part); //return self. return this; } public QueryBuilder And(string path, ConditionOperators conditionOperator, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField) => Compare(path, conditionOperator, value, convertStrategy: convertStrategy, and: true); public QueryBuilder Or(string path, ConditionOperators conditionOperator, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField) => Compare(path, conditionOperator, value, convertStrategy: convertStrategy, and: false); public QueryBuilder And(Action> subQuery) => SubQuery(subQuery, true); public QueryBuilder Or(Action> subQuery) => SubQuery(subQuery, false); public virtual IQueryable Build() { // the query. var query = Query; // execute the filters. query = BuildFilters(query); return query; } protected virtual IQueryable BuildFilters(IQueryable query) { var parameter = Expression.Parameter(typeof(T), "t"); var expression = BuildFilterExpression(parameter, Parts); var lambda = Expression.Lambda>(expression, parameter); query = query.Where(lambda); return query; } protected virtual Expression BuildFilterExpression(ParameterExpression parameter, List filters) { Expression ret = null; filters.ForEach(filter => { Expression innerExpression; if (filter.Parts?.Any() == true) innerExpression = BuildFilterExpression(parameter, filter.Parts); else innerExpression = BuildFilterExpression(parameter, filter); if (ret != null) ret = filter.And ? Expression.And(ret, innerExpression) : Expression.Or(ret, innerExpression); else ret = innerExpression; }); return ret; } protected virtual Expression BuildFilterExpression(ParameterExpression parameter, QueryBuilderFilter filter) { var member = QueryableHelpers.ResolvePathForExpression(parameter, filter.Path); var constant = QueryableHelpers.ResolveConstant(member, filter.Value, filter.ConvertStrategy); var expression = QueryableHelpers.GetConditionExpressionForMember(parameter, member, filter.ConditionOperator, constant); return expression; } } }