Skip to content

Commit

Permalink
Add parenthesis on filter
Browse files Browse the repository at this point in the history
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"
  • Loading branch information
sfreidahl committed Jan 9, 2023
1 parent 0168279 commit 11c5a1e
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,11 @@ protected override string VisitLambdaExpression(LambdaExpression lambdaExpressio

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,
Expand Down
23 changes: 23 additions & 0 deletions test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,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<ODataTypeEntity>(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)]
Expand Down

0 comments on commit 11c5a1e

Please sign in to comment.