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 QueryFilterPart { 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 QueryFilterPart(); 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 = ExecuteFilters(query); return query; } protected virtual IQueryable ExecuteFilters(IQueryable query) { var parameter = Expression.Parameter(typeof(T), "t"); var expression = BuildExpression(parameter, Parts); var lambda = Expression.Lambda>(expression, parameter); query = query.Where(lambda); return query; } protected virtual Expression BuildExpression(ParameterExpression parameter, List parts) { Expression ret = null; parts.ForEach(part => { Expression innerExpression; if (part.Parts?.Any() == true) innerExpression = BuildExpression(parameter, part.Parts); else innerExpression = BuildExpression(parameter, part); if (ret != null) ret = part.And ? Expression.And(ret, innerExpression) : Expression.Or(ret, innerExpression); else ret = innerExpression; }); return ret; } protected virtual Expression BuildExpression(ParameterExpression parameter, QueryFilterPart part) { var member = QueryableHelpers.ResolvePathForExpression(parameter, part.Path); var constant = QueryableHelpers.ResolveConstant(member, part.Value, part.ConvertStrategy); var expression = QueryableHelpers.GetConditionExpressionForMember(parameter, member, part.ConditionOperator, constant); return expression; } } }