From 1575f58d940bf2ce352a2143b0cf41f1351df9cf Mon Sep 17 00:00:00 2001 From: sfreidahl Date: Tue, 7 Jun 2022 14:58:35 +0200 Subject: [PATCH] Add parenthesis on filter When combining several filters by calling Filter() multiple times, they will be joined by "and" which is "fine". The issues comes when there's an or in one of the filters, which will produce unexpected results. e.g. Filter(x => x.Foo == "some string") Filter(x => x.Bar == 1 || x.Bar == 2 ) Should be: "(Foo eq 'some string') and (Bar eq 1 or Bar eq 2)" But will be: "Foo eq 'some string' and Bar eq 1 or Bar eq 2" --- .../ODataOptionFilterExpressionVisitor.cs | 7 +++--- .../ODataQueryCollectionTest.cs | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/OData.QueryBuilder/Expressions/Visitors/ODataOptionFilterExpressionVisitor.cs b/src/OData.QueryBuilder/Expressions/Visitors/ODataOptionFilterExpressionVisitor.cs index b3677ca2..9f8a7b18 100644 --- a/src/OData.QueryBuilder/Expressions/Visitors/ODataOptionFilterExpressionVisitor.cs +++ b/src/OData.QueryBuilder/Expressions/Visitors/ODataOptionFilterExpressionVisitor.cs @@ -277,10 +277,11 @@ protected override string VisitLambdaExpression(LambdaExpression topExpression, private bool HasParenthesis(ExpressionType expressionType) { - var hasParenthesis = _expressionType.HasValue && expressionType switch + + var hasParenthesis = expressionType switch { - ExpressionType.And => true, - ExpressionType.AndAlso => true, + ExpressionType.And => true && _expressionType.HasValue, + ExpressionType.AndAlso => true && _expressionType.HasValue, ExpressionType.Or => true, ExpressionType.OrElse => true, _ => false, diff --git a/test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs b/test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs index b28b7891..97948e02 100644 --- a/test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs +++ b/test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs @@ -1170,6 +1170,29 @@ public void ODataQueryBuilderList_Filter_support_parentheses_Success() $" and ODataKind/ODataCode/Code in ('123','512')"); } + [Fact(DisplayName = "Multiple filters wrap or in parenthesis => Success")] + public void ODataQueryBuilderList_Multiple_filters_wrap_or_in_parenthesis_Success() + { + var constStrIds = new[] { "123", "512" }; + var constValue = 3; + + var uri = _odataQueryBuilderDefault + .For(s => s.ODataType) + .ByList() + .Filter((s, f, o) => s.IdRule == constValue) + .Filter((s, f, o) => s.IsActive) + .Filter((s, f, o) => (f.Date(s.EndDate.Value) == default(DateTimeOffset?) || s.EndDate > DateTime.Today), useParenthesis: true) + .Filter((s, f, o) => (f.Date((DateTimeOffset)s.BeginDate) != default(DateTime?) || f.Date((DateTime)s.BeginDate) <= DateTime.Now), useParenthesis: true) + .Filter((s, f, o) => (o.In(s.ODataKind.ODataCode.Code, constStrIds))) + .ToUri(); + + uri.Should().Be($"http://mock/odata/ODataType?$filter=IdRule eq 3" + + $" and IsActive" + + $" and (date(EndDate) eq null or EndDate gt {DateTime.Today:s}Z)" + + $" and (date(BeginDate) ne null or date(BeginDate) le {DateTime.Now:s}Z)" + + $" and ODataKind/ODataCode/Code in ('123','512')"); + } + [Theory(DisplayName = "Count value => Success")] [InlineData(true)] [InlineData(false)]