From 0fc4cfb908b39c80bfcb8cf78b7f918502e97bc8 Mon Sep 17 00:00:00 2001 From: Mehdi Oueldi Date: Thu, 26 May 2022 02:10:36 +0200 Subject: [PATCH 1/3] Query introduce dynamic query as extensions --- .../DynamicQueryExtensions.cs | 18 +++++++++ .../ExpressionBuilderTests.cs | 37 +++++++++++++++++++ .../TableStorageQueryBuilderTests.cs | 21 +++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs diff --git a/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs b/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs new file mode 100644 index 0000000..ea0d975 --- /dev/null +++ b/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace Azure.EntityServices.Queries +{ + public static class DynamicQueryExtensions + { + public static IFilterOperator WithEach(this IFilterOperator query, IEnumerable list, Func, IFilterOperator> action) + { + var dynamicQuery = query; + foreach (var item in list) + { + dynamicQuery = action(item, dynamicQuery); + } + return dynamicQuery; + } + } +} \ No newline at end of file diff --git a/tests/Azure.EntityServices.Tests/QueryExpressions/ExpressionBuilderTests.cs b/tests/Azure.EntityServices.Tests/QueryExpressions/ExpressionBuilderTests.cs index e9f1b38..0469e63 100644 --- a/tests/Azure.EntityServices.Tests/QueryExpressions/ExpressionBuilderTests.cs +++ b/tests/Azure.EntityServices.Tests/QueryExpressions/ExpressionBuilderTests.cs @@ -101,5 +101,42 @@ public void Should_BuildGroup_Query_Expression_With_DefaultInstructions() .Should() .Be("TenantId Equal '10' And (Created GreaterThan '2012-04-21T18:25:43.0000000+00:00' And LastName Equal 'test' Or Created LessThan '2012-04-21T18:25:43.0000000+00:00') Not Enabled Equal 'True' And (Created GreaterThan '2012-04-21T18:25:43.0000000+00:00' Or Created LessThan '2012-04-21T18:25:43.0000000+00:00')"); } + + [TestMethod] + public void Should_BuildGroup_Dynamic_Query_Expression() + { + var builder = new MockedExpressionBuilder(); + + var dynamicQuery = builder.Query + .Where(p => p.TenantId).Equal("50"); + for (var i = 0; i < 10; i++) + { + dynamicQuery = dynamicQuery.Or(p => p.FirstName).Equal($"do {i}"); + } + + var queryStr = builder.Build(); + + queryStr.Trim() + .Should() + .Be("TenantId Equal '50' Or FirstName Equal 'do 0' Or FirstName Equal 'do 1' Or FirstName Equal 'do 2' Or FirstName Equal 'do 3' Or FirstName Equal 'do 4' Or FirstName Equal 'do 5' Or FirstName Equal 'do 6' Or FirstName Equal 'do 7' Or FirstName Equal 'do 8' Or FirstName Equal 'do 9'"); + } + + [TestMethod] + public void Should_BuildGroup_Dynamic_Query_Expression_With_Extension_Helper() + { + var builder = new MockedExpressionBuilder(); + + var dynamicQuery = builder.Query + .Where(p => p.TenantId).Equal("50"); + + dynamicQuery.WithEach(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, (item, q) => + q.Or(p => p.FirstName).Equal($"do {item}")); + + var queryStr = builder.Build(); + + queryStr.Trim() + .Should() + .Be("TenantId Equal '50' Or FirstName Equal 'do 0' Or FirstName Equal 'do 1' Or FirstName Equal 'do 2' Or FirstName Equal 'do 3' Or FirstName Equal 'do 4' Or FirstName Equal 'do 5' Or FirstName Equal 'do 6' Or FirstName Equal 'do 7' Or FirstName Equal 'do 8' Or FirstName Equal 'do 9'"); + } } } \ No newline at end of file diff --git a/tests/Azure.EntityServices.Tests/QueryExpressions/TableStorageQueryBuilderTests.cs b/tests/Azure.EntityServices.Tests/QueryExpressions/TableStorageQueryBuilderTests.cs index 0f924b0..7a38fdf 100644 --- a/tests/Azure.EntityServices.Tests/QueryExpressions/TableStorageQueryBuilderTests.cs +++ b/tests/Azure.EntityServices.Tests/QueryExpressions/TableStorageQueryBuilderTests.cs @@ -135,5 +135,26 @@ public void Should_Use_filter_with_default_values() .Be("RowKey gt 'Created-$' and RowKey lt 'Created-$~' and _deleted_tag_ eq false and TenantId eq '10' and Updated eq datetime'1601-01-01T00:00:00.0000000Z' and LocalUpdated eq datetime'1601-01-01T00:00:00.0000000Z' or Enabled eq null or Altitude eq null"); } + [TestMethod] + public void Should_Use_Multi_PartitionKey_filter() + { + var builder = new TableStorageQueryBuilder(new TagFilterExpression("Created")); + + (builder.Query as TagFilterExpression) + .WherePartitionKey() + .Equal("partition1") + .OrPartitionKey() + .Equal("partition2") + .OrPartitionKey() + .Equal("Partition3"); + + var queryStr = builder.Build(); + + queryStr.Trim() + .Should() + .Be("PartitionKey eq 'partition1' or PartitionKey eq 'partition2' or PartitionKey eq 'Partition3'"); + + } + } } \ No newline at end of file From ad5abaa2061f60e5d1b7524b912f2c5e8f9e0174 Mon Sep 17 00:00:00 2001 From: Mehdi Oueldi Date: Thu, 26 May 2022 02:10:59 +0200 Subject: [PATCH 2/3] chore --- .../HelperExtensions/DynamicQueryExtensions.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs b/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs index ea0d975..8148b70 100644 --- a/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs +++ b/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs @@ -5,6 +5,15 @@ namespace Azure.EntityServices.Queries { public static class DynamicQueryExtensions { + /// + /// Build query filters by iterate on each given collection item + /// + /// + /// Generic collection + /// + /// + /// + /// public static IFilterOperator WithEach(this IFilterOperator query, IEnumerable list, Func, IFilterOperator> action) { var dynamicQuery = query; From c11424098cb42fff8a3ef8b8325b6739521ca894 Mon Sep 17 00:00:00 2001 From: Mehdi Oueldi Date: Mon, 6 Feb 2023 22:53:05 +0100 Subject: [PATCH 3/3] added dynamic query extensions --- .../DynamicQueryExtensions.cs | 39 +++++++++++++ .../IQueryFilter.cs | 5 +- .../ExpressionBuilderTests.cs | 58 ++++++++++++++++++- 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs b/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs index 8148b70..fa48821 100644 --- a/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs +++ b/src/Azure.EntityServices.Queries/HelperExtensions/DynamicQueryExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace Azure.EntityServices.Queries { @@ -23,5 +24,43 @@ public static IFilterOperator WithEach(this IFilterOperator query, I } return dynamicQuery; } + + /// + /// Build a filter to check if current field value was present in given list + /// + /// + /// + /// + /// + /// + public static IFilterOperator In(this IQueryFilter query, params P[] values) + { + IQuery nextQuery = (IQuery)query; + foreach (var item in values.SkipLast(1)) + { + nextQuery = (IQuery)(nextQuery as IQueryFilter).Equal(item).Or(query.PropertyName); + } + (nextQuery as IQueryFilter).Equal(values.Last()); + return nextQuery as IFilterOperator; + } + + /// + /// Build a filter to check if current field value was not present in given list + /// + /// + /// + /// + /// + /// + public static IFilterOperator NotIn(this IQueryFilter query, params P[] values) + { + IQuery nextQuery = (IQuery)query; + foreach (var item in values.SkipLast(1)) + { + nextQuery = (IQuery)(nextQuery as IQueryFilter).NotEqual(item).And(query.PropertyName); + } + (nextQuery as IQueryFilter).NotEqual(values.Last()); + return nextQuery as IFilterOperator; + } } } \ No newline at end of file diff --git a/src/Azure.EntityServices.Queries/IQueryFilter.cs b/src/Azure.EntityServices.Queries/IQueryFilter.cs index 6a25866..e7ca300 100644 --- a/src/Azure.EntityServices.Queries/IQueryFilter.cs +++ b/src/Azure.EntityServices.Queries/IQueryFilter.cs @@ -7,8 +7,11 @@ public interface IQueryFilter : IQueryFilter public interface IQueryFilter { + string PropertyName { get; } + IFilterOperator AddFilterCondition(string comparison, P value); + IFilterOperator AddFilterCondition(string comparison, object value, Type type); - + } } \ No newline at end of file diff --git a/tests/Azure.EntityServices.Tests/QueryExpressions/ExpressionBuilderTests.cs b/tests/Azure.EntityServices.Tests/QueryExpressions/ExpressionBuilderTests.cs index 0469e63..701a070 100644 --- a/tests/Azure.EntityServices.Tests/QueryExpressions/ExpressionBuilderTests.cs +++ b/tests/Azure.EntityServices.Tests/QueryExpressions/ExpressionBuilderTests.cs @@ -122,7 +122,7 @@ public void Should_BuildGroup_Dynamic_Query_Expression() } [TestMethod] - public void Should_BuildGroup_Dynamic_Query_Expression_With_Extension_Helper() + public void Should_BuildGroup_Dynamic_Query_Expression_WithEach_Extension_Helper() { var builder = new MockedExpressionBuilder(); @@ -138,5 +138,61 @@ public void Should_BuildGroup_Dynamic_Query_Expression_With_Extension_Helper() .Should() .Be("TenantId Equal '50' Or FirstName Equal 'do 0' Or FirstName Equal 'do 1' Or FirstName Equal 'do 2' Or FirstName Equal 'do 3' Or FirstName Equal 'do 4' Or FirstName Equal 'do 5' Or FirstName Equal 'do 6' Or FirstName Equal 'do 7' Or FirstName Equal 'do 8' Or FirstName Equal 'do 9'"); } + + [TestMethod] + public void Should_BuildGroup_Dynamic_Query_Expression_In_Extension_Helper() + { + var builder = new MockedExpressionBuilder(); + + var dynamicQuery = builder.Query + .Where(p => p.TenantId).Equal("50") + .And(p => p.LastName) + .In("Doe"); + + var queryStr = builder.Build(); + + queryStr.Trim() + .Should() + .Be("TenantId Equal '50' And LastName Equal 'Doe'"); + + dynamicQuery = builder.Query + .Where(p => p.TenantId).Equal("50") + .And("LastName") + .In("Doe", "Kent"); + + queryStr = builder.Build(); + + queryStr.Trim() + .Should() + .Be("TenantId Equal '50' And LastName Equal 'Doe' Or LastName Equal 'Kent'"); + } + + [TestMethod] + public void Should_BuildGroup_Dynamic_Query_Expression_NotIn_Extension_Helper() + { + var builder = new MockedExpressionBuilder(); + + var dynamicQuery = builder.Query + .Where(p => p.TenantId).Equal("50") + .And(p => p.LastName) + .NotIn("Doe"); + + var queryStr = builder.Build(); + + queryStr.Trim() + .Should() + .Be("TenantId Equal '50' And LastName NotEqual 'Doe'"); + + dynamicQuery = builder.Query + .Where(p => p.TenantId).Equal("50") + .And("LastName") + .NotIn("Doe", "Kent"); + + queryStr = builder.Build(); + + queryStr.Trim() + .Should() + .Be("TenantId Equal '50' And LastName NotEqual 'Doe' And LastName NotEqual 'Kent'"); + } } } \ No newline at end of file