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 partial class WhereBuilder { public IQueryable Query { get; set; } public Type QueryableType { get; set; } public List Filters { get; protected set; } = new List(); public WhereBuilder(IQueryable query) { Query = query; QueryableType = query.ElementType; } public bool IsNullCheckingEnabled { get; protected set; } = false; public virtual WhereBuilder NullChecking(bool check = true) { IsNullCheckingEnabled = check; return this; } public virtual WhereBuilder Compare(string path, ConditionOperators conditionOperators, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, bool and = true, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) { Filters.Add(new WhereBuilderCondition { And = and, ConditionOperator = conditionOperators, Path = path, Value = value, ConvertStrategy = convertStrategy, CollectionHandling = collectionHandling, StringComparisation = stringComparision }); return this; } public virtual WhereBuilder SubQuery(Action subQuery, bool and = true) { // create query builder for same type. var qb = new WhereBuilder(Query); qb.NullChecking(IsNullCheckingEnabled); // callback. subQuery(qb); // create a query part. var part = new WhereBuilderCondition(); part.And = and; part.Conditions = qb.Filters; Filters.Add(part); //return self. return this; } public virtual IQueryable Build() { // the query. var query = Query; if (Filters == null || Filters?.Count() == 0) return query; // shared parameter. var sharedParameter = Expression.Parameter(QueryableType, "t"); // build the expression. var filterExpressionMerged = BuildConditionExpression(sharedParameter, Filters); // create the where expression. var whereExpression = Expression.Call(typeof(Queryable), "Where", new[] { query.ElementType }, query.Expression, filterExpressionMerged); // lets see what happens here. query = query.Provider.CreateQuery(whereExpression); return query; } protected virtual Expression BuildConditionExpression(ParameterExpression parameter, List filters) { Expression temp = null; filters.ForEach(filter => { Expression innerExpression; if (filter.Conditions?.Any() == true) innerExpression = BuildConditionExpression(parameter, filter.Conditions); else innerExpression = BuildConditionExpression(parameter, filter); if (temp == null) { temp = innerExpression; } else { var body = ((LambdaExpression)temp).Body; var innerEpressionBody = ((LambdaExpression)innerExpression).Body; if (filter.And) temp = Expression.Lambda(Expression.AndAlso(body, innerEpressionBody), parameter); else temp = Expression.Lambda(Expression.OrElse(body, innerEpressionBody), parameter); } }); return temp; } protected virtual Expression BuildConditionExpression(ParameterExpression parameter, WhereBuilderCondition filter) { var ret = QueryableHelpers.CreateConditionExpression( parameter.Type, filter.Path, filter.ConditionOperator, filter.Value, filter.ConvertStrategy, filter.CollectionHandling, parameter: parameter, nullChecking: IsNullCheckingEnabled, stringComparision: filter.StringComparisation ); return ret; } } }