diff --git a/src/OData.QueryBuilder/Conventions/Operators/IODataOperator.cs b/src/OData.QueryBuilder/Conventions/Operators/IODataOperator.cs index 0d0688cd..3246876d 100644 --- a/src/OData.QueryBuilder/Conventions/Operators/IODataOperator.cs +++ b/src/OData.QueryBuilder/Conventions/Operators/IODataOperator.cs @@ -9,6 +9,8 @@ public interface IODataOperator bool All(IEnumerable columnName, Func func); + bool Any(IEnumerable columnName); + bool Any(IEnumerable columnName, Func func); } } diff --git a/src/OData.QueryBuilder/Expressions/Visitors/ODataOptionFilterExpressionVisitor.cs b/src/OData.QueryBuilder/Expressions/Visitors/ODataOptionFilterExpressionVisitor.cs index 494dea75..e85ec0aa 100644 --- a/src/OData.QueryBuilder/Expressions/Visitors/ODataOptionFilterExpressionVisitor.cs +++ b/src/OData.QueryBuilder/Expressions/Visitors/ODataOptionFilterExpressionVisitor.cs @@ -78,7 +78,22 @@ protected override string VisitMethodCallExpression(MethodCallExpression methodC return $"{all0}/{nameof(IODataOperator.All).ToLowerInvariant()}({all1})"; case nameof(IODataOperator.Any): var any0 = VisitExpression(methodCallExpression.Arguments[0]); - var any1 = VisitExpression(methodCallExpression.Arguments[1]); + var any1 = default(string); + + if (methodCallExpression.Arguments.Count > 1) + { + any1 = VisitExpression(methodCallExpression.Arguments[1]); + + if (any1.IsNullOrQuotes()) + { + if (!_odataQueryBuilderOptions.SuppressExceptionOfNullOrEmptyOperatorArgs) + { + throw new ArgumentException("Func is null"); + } + + return default; + } + } return $"{any0}/{nameof(IODataOperator.Any).ToLowerInvariant()}({any1})"; case nameof(IODataFunction.Date): diff --git a/test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs b/test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs index 70b77e43..aff64968 100644 --- a/test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs +++ b/test/OData.QueryBuilder.Test/ODataQueryCollectionTest.cs @@ -333,6 +333,50 @@ public void ODataQueryBuilderList_Filter_Any_With_Func_Success() uri.Should().Be("http://mock/odata/ODataType?$filter=ODataKind/ODataCodes/any(v:date(v/Created) eq 2019-02-09T00:00:00Z)"); } + [Fact(DisplayName = "(ODataQueryBuilderList) Filter Any without func => Success")] + public void ODataQueryBuilderList_Filter_Any_Without_Func() + { + var uri = _odataQueryBuilderDefault + .For(s => s.ODataType) + .ByList() + .Filter((s, f, o) => o.Any(s.Labels)) + .ToUri(); + + uri.Should().Be("http://mock/odata/ODataType?$filter=Labels/any()"); + } + + [Fact(DisplayName = "(ODataQueryBuilderList) Filter Any with func null supressed => Success")] + public void ODataQueryBuilderList_Filter_Any_With_Func_null_Supressed() + { + var odataQueryBuilderOptions = new ODataQueryBuilderOptions { SuppressExceptionOfNullOrEmptyOperatorArgs = true }; + var odataQueryBuilder = new ODataQueryBuilder( + _commonFixture.BaseUri, odataQueryBuilderOptions); + + var func = default(Func); + + var uri = odataQueryBuilder + .For(s => s.ODataType) + .ByList() + .Filter((s, _, o) => o.Any(s.Labels, func)) + .ToUri(); + + uri.Should().Be("http://mock/odata/ODataType?$filter="); + } + + [Fact(DisplayName = "(ODataQueryBuilderList) Filter Any with func null => ArgumentException")] + public void ODataQueryBuilderList_Filter_Any_With_Func_null() + { + var func = default(Func); + + _odataQueryBuilderDefault.Invoking( + (r) => r + .For(s => s.ODataType) + .ByList() + .Filter((s, _, o) => o.Any(s.Labels, func)) + .ToUri()) + .Should().Throw().WithMessage("Func is null"); + } + [Fact(DisplayName = "Expand,Filter,Select,OrderBy,OrderByDescending,Skip,Top,Count => Success")] public void ODataQueryBuilderList_Expand_Filter_Select_OrderBy_OrderByDescending_Skip_Top_Count_Success() {