QueryNode VisitFilter(Filter filter) { QueryNode result = OptimizeFilter(filter); filter = result as Filter; if (filter == null) return result; return ReorderFilter(filter); }
/// <summary> /// Optimizes the filter; but does not try to combine nested filter (etc.) /// </summary> QueryNode OptimizeFilter(Filter filter) { QueryNode target = Visit(filter.Target); List<LambdaExpression> newConditions = new List<LambdaExpression>(); OptimizeQueryExpressionVisitor optimizer = new OptimizeQueryExpressionVisitor(); foreach (LambdaExpression expr in filter.Conditions) { Expression optimizedExpr = optimizer.Visit(expr.Body); if (optimizedExpr.NodeType == ExpressionType.Constant && optimizedExpr.Type == typeof(bool)) { bool val = (bool)((ConstantExpression)optimizedExpr).Value; if (val) continue; } newConditions.Add(Expression.Lambda(optimizedExpr, expr.Parameters)); } if (newConditions.Count == 0) return target; else return new Filter(target, newConditions.ToArray()); }
/// <summary> /// Tries to combine nested filters; /// move 'MergeByName' nodes out of filter, if possible /// </summary> QueryNode ReorderFilter(Filter filter) { if (filter.Target is Filter) { // x.Filter(y).Filter(z) -> x.Filter(y && z) Filter innerFilter = (Filter)filter.Target; return ReorderFilter(new Filter(innerFilter.Target, innerFilter.Conditions.Concat(filter.Conditions).ToArray())); } else if (filter.Target is MergeByName) { // x.MergeByName().Filter(<criteria>) -> x.Filter(x, <criteria>).MergeByName() for some safe criterias QueryNode innerTarget = filter.Target.Target; var conditionsToMoveIntoFilter = filter.Conditions.Where(c => IsConditionSafeVisitor.Test(c, SafeMembersForMoveIntoMergeByName)).ToArray(); if (conditionsToMoveIntoFilter.Length != 0) { MergeByName newTarget = new MergeByName(ReorderFilter(new Filter(innerTarget, conditionsToMoveIntoFilter))); var conditionsKeptOutsideFilter = filter.Conditions.Except(conditionsToMoveIntoFilter).ToArray(); if (conditionsKeptOutsideFilter.Length == 0) return newTarget; else return new Filter(newTarget, conditionsKeptOutsideFilter); } else { return filter; } } else { return filter; } }