Skip to content

Commit

Permalink
fix queries In and NotIn behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
Mehdi Oueldi committed Feb 10, 2023
1 parent f4c42ee commit 633cf66
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ protected virtual string Build(IFilterExpression<T> expression)
if (expression.Group.Count > 0)
{
foreach (var operation in expression.Group)
{
{
queryBuilder.Append($" {InstructionsProvider.Get(operation.GroupOperator)} (");
queryBuilder.Append(Build(operation));
queryBuilder.Append(")");
}
}
}
queryBuilder.Append($" {InstructionsProvider.Get(expression.Operator)} ");

queryBuilder.Append(Build(expression.NextOperation));

return queryBuilder.ToString().Trim();
Expand Down
6 changes: 3 additions & 3 deletions src/Azure.EntityServices.Queries/FilterExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public virtual IFilterExpression<T> Factory<P>()
public List<IFilterExpression<T>> Group { get; } = new List<IFilterExpression<T>>();

public IFilterExpression<T> NextOperation { get; set; }
public IFilterExpression<T> LastOperation { get; set; }
public IFilterExpression<T> PrevOperation { get; set; }

public IQueryFilter<T, P> AddOperator<P>(string expressionOperator, Expression<Func<T, P>> property)
{
Expand All @@ -40,7 +40,7 @@ public IQueryFilter<T, P> AddOperator<P>(string expressionOperator, Expression<F

newOperation.PropertyName = prop.Name;
newOperation.PropertyType = prop.PropertyType;
newOperation.LastOperation = this;
newOperation.PrevOperation = this;

NextOperation = newOperation;
return newOperation as IQueryFilter<T,P>;
Expand All @@ -53,7 +53,7 @@ public IQueryFilter<T> AddOperator(string expressionOperator, string property)

newOperation.PropertyName = property;
newOperation.PropertyType = typeof(object);
newOperation.LastOperation = this;
newOperation.PrevOperation = this;

NextOperation = newOperation;
return newOperation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,16 @@ public static IFilterOperator<T> WithEach<T, U>(this IFilterOperator<T> query, I
public static IFilterOperator<T> NotIn<T, P>(this IQueryFilter<T, P> query, params P[] values)
{
var exp = query as IFilterExpression<T>;

exp.LastOperation.AddGroupExpression(string.IsNullOrEmpty(exp.LastOperation.PropertyName) ? "" : "And",
exp.PrevOperation.AddGroupExpression(string.IsNullOrEmpty(exp.PrevOperation.PropertyName) ? "" : "And",
p => p.Where(exp.PropertyName)
._NotIn(values));

//ignore current expression because we need override and keep the previous expression
exp.PropertyName = null;
exp.Operator = null;

return exp.LastOperation;
exp.PrevOperation.Operator = null;
return exp.PrevOperation;
}
/// <summary>
/// Build a filter to check if current field value was present in given list
Expand All @@ -58,13 +60,15 @@ public static IFilterOperator<T> In<T, P>(this IQueryFilter<T, P> query, params

var exp = query as IFilterExpression<T>;

exp.LastOperation.AddGroupExpression(string.IsNullOrEmpty(exp.LastOperation.PropertyName) ? "" : "And",
exp.PrevOperation.AddGroupExpression(string.IsNullOrEmpty(exp.PrevOperation.PropertyName) ? "" : "And",
p => p.Where(exp.PropertyName)
._In(values));

//ignore current expression because we need override and keep the previous expression
exp.PropertyName = null;
exp.Operator = null;

return exp.LastOperation;
exp.PrevOperation.Operator = null;
return exp.PrevOperation;
}

private static IFilterOperator<T> _In<T, P>(this IQueryFilter<T> query, P[] values)
Expand All @@ -75,7 +79,7 @@ private static IFilterOperator<T> _In<T, P>(this IQueryFilter<T> query, P[] valu
nextQuery = (IQuery<T>)(nextQuery as IQueryFilter<T>)
.Equal(item)
.Or((query as IFilterExpression<T>).PropertyName);
}
}
(nextQuery as IQueryFilter<T>).Equal(values.Last());
return nextQuery as IFilterOperator<T>;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Azure.EntityServices.Queries/IQueryExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public interface IFilterExpression<T> : IFilterOperator<T>, IQueryFilter<T>, IQu
List<IFilterExpression<T>> Group { get; }
public string GroupOperator { get; set; }
IFilterExpression<T> NextOperation { get; set; }
IFilterExpression<T> LastOperation { get; set; }
IFilterExpression<T> PrevOperation { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
Expand All @@ -15,7 +15,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Common.Samples\Common.Samples.csproj" />
<ProjectReference Include="..\..\samples\Common.Samples\Common.Samples.csproj" />
<ProjectReference Include="..\..\src\Azure.EntityServices.Blobs\Azure.EntityServices.Blobs.csproj" />
<ProjectReference Include="..\..\src\Azure.EntityServices.Tables\Azure.EntityServices.Tables.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public void Should_Build_TableStorage_Query_Expression_With_Grouped_Filter_Insid
.AndNot(p => p
.Where(p => p.Created).GreaterThan(DateTimeOffset.Parse("2012-04-21T18:25:43Z"))
.Or(p => p.Created).LessThan(DateTimeOffset.Parse("2012-04-21T18:25:43Z")))
.OrNot(p => p.Where(p=>p.Enabled).Equal(true));
.OrNot(p => p.Where(p => p.Enabled).Equal(true));

var queryStr = builder.Build();

Expand Down Expand Up @@ -166,55 +166,57 @@ public void Should_BuildGroup_Dynamic_Query_Expression_In_Extension_Helper()

var dynamicQuery = builder.Query
.Where(p => p.TenantId).Equal("50")
.And(p => p.LastName)
.In("Doe");
.And(p => p.LastName).In("Doe");

var queryStr = builder.Build();

queryStr.Trim()
.Should()
.Be("TenantId Equal '50' And LastName Equal 'Doe'");
.Be("TenantId Equal '50' And (LastName Equal 'Doe')");

dynamicQuery = builder.Query
.Where(p => p.TenantId).Equal("50")
.And(p=>p
.Where("LastName")
.In("Doe", "Kent"));

.And("LastName")
.In("Doe", "Kent");

queryStr = builder.Build();

queryStr.Trim()
.Should()
.Be("TenantId Equal '50' And LastName Equal 'Doe' Or LastName Equal 'Kent'");
.Be("TenantId Equal '50' And (LastName Equal 'Doe' Or LastName Equal 'Kent')");
}

[TestMethod]
public void Should_BuildGroup_Dynamic_Query_Expression_NotIn_Extension_Helper()
public void Should_BuildGroup_Dynamic_SubQuery_With_In_Extension_Helper()
{
var builder = new MockedExpressionBuilder<PersonEntity>();

var dynamicQuery = builder.Query
.Where(p => p.TenantId).Equal("50")
.And(p => p.LastName)
.NotIn("Doe");
builder.Query
.Where(p => p.TenantId).Equal("50")
.And(p => p
.Where("LastName")
.In("Doe", "Kent"));

var queryStr = builder.Build();

queryStr.Trim()
.Should()
.Be("TenantId Equal '50' And LastName NotEqual 'Doe'");
.Be("TenantId Equal '50' And ((LastName Equal 'Doe' Or LastName Equal 'Kent'))");
}

dynamicQuery = builder.Query
.Where(p => p.TenantId).Equal("50")
.And("LastName")
.NotIn("Doe", "Kent");
[TestMethod]
public void Should_BuildGroup_Dynamic_Query_Expression_NotIn_Extension_Helper()
{
var builder = new MockedExpressionBuilder<PersonEntity>();

queryStr = builder.Build();
builder.Query
.Where(p => p.TenantId).Equal("50")
.And("LastName").NotIn("Doe", "Kent");

var queryStr = builder.Build();

queryStr.Trim()
.Should()
.Be("TenantId Equal '50' And LastName NotEqual 'Doe' And LastName NotEqual 'Kent'");
.Be("TenantId Equal '50' And (LastName NotEqual 'Doe' And LastName NotEqual 'Kent')");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public void Should_Build_TableStorage_Query_Expression()
.And(p => p.TenantId).Equal("10")
.And(p => p
.Where(p => p.Created).GreaterThan(DateTimeOffset.Parse("2012-04-21T18:25:43Z"))
.Or(p => p.Created).LessThan(DateTimeOffset.Parse("2012-04-21T18:25:43Z")))
.Or(p => p.Created).LessThan(DateTimeOffset.Parse("2012-04-21T18:25:43Z"))
)
.And(p => p.Enabled).Equal(true);

var queryStr = builder.Build();
Expand Down Expand Up @@ -70,8 +71,7 @@ public void Should_Use_Tag_GreaterThanOrEqual_Extension()
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.WhereTag("Created")
.GreaterThanOrEqual("2022-10-22")
.WhereTag("Created").GreaterThanOrEqual("2022-10-22")
.And(p => p.TenantId).Equal("10");

var queryStr = builder.Build();
Expand All @@ -87,8 +87,7 @@ public void Should_Use_Tag_LessThanOrEqual_Extension()
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.WhereTag("Created")
.LessThanOrEqual("2022-10-22")
.WhereTag("Created").LessThanOrEqual("2022-10-22")
.And(p => p.TenantId).Equal("10");

var queryStr = builder.Build();
Expand Down Expand Up @@ -143,14 +142,10 @@ public void Should_Build_Table_Filter_Expression_With_Invariant_Floating_Point_V
var builder = new TableStorageQueryBuilder<PersonEntity>(new FilterExpression<PersonEntity>());
builder
.Query
.WherePartitionKey()
.Equal("tenantId")
.And(p => p.Latitude)
.Equal(48.77309806265856)
.And(p => p.Distance)
.Equal(148.45648566856M)
.And(p => p.BankAmount)
.Equal(1248.7731F);
.WherePartitionKey().Equal("tenantId")
.And(p => p.Latitude).Equal(48.77309806265856)
.And(p => p.Distance).Equal(148.45648566856M)
.And(p => p.BankAmount).Equal(1248.7731F);

var result = builder.Build();
result.Should()
Expand All @@ -163,12 +158,9 @@ public void Should_Use_Multi_PartitionKey_filter()
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>("Created"));

(builder.Query as TagFilterExpression<PersonEntity>)
.WherePartitionKey()
.Equal("partition1")
.OrPartitionKey()
.Equal("partition2")
.OrPartitionKey()
.Equal("Partition3");
.WherePartitionKey().Equal("partition1")
.OrPartitionKey().Equal("partition2")
.OrPartitionKey().Equal("Partition3");

var queryStr = builder.Build();

Expand Down Expand Up @@ -199,8 +191,7 @@ public void Should_Use_IncludeTags_To_Get_All_Entities_Included_All_Tags()

(builder.Query as TagFilterExpression<PersonEntity>)
.IncludeTags()
.WherePartitionKey()
.Equal("tenant1");
.WherePartitionKey().Equal("tenant1");

var queryStr = builder.Build();

Expand All @@ -215,8 +206,7 @@ public void Should_Use_In_Filter_With_Tag_Prop()
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.Where("PartitionKey")
.In("value1", "value2", "value3");
.Where("PartitionKey").In("value1", "value2", "value3");

var queryStr = builder.Build();
queryStr.Trim()
Expand All @@ -230,12 +220,9 @@ public void Should_Use_In_Filter_Inside_ExpressionFilter_Prop2()
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.Where("prop1s")
.Equal("value")
.And("tenant1")
.In("tag1", "tag2", "tag3")
.And("prop2")
.Equal("newValue");
.Where("prop1s").Equal("value")
.And("tenant1").In("tag1", "tag2", "tag3")
.And("prop2").Equal("newValue");

var queryStr = builder.Build();

Expand All @@ -250,10 +237,8 @@ public void Should_Use_In_Filter_At_Start_Of_ExpressionFilter_Prop2()
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.Where("tenant1")
.In("tag1", "tag2", "tag3")
.And("prop2")
.Equal("newValue");
.Where("tenant1").In("tag1", "tag2", "tag3")
.And("prop2").Equal("newValue");

var queryStr = builder.Build();

Expand All @@ -268,8 +253,7 @@ public void Should_Use_NotIn_Filter_With_Tag_Prop()
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.Where("PartitionKey")
.NotIn("value1", "value2", "value3");
.Where("PartitionKey").NotIn("value1", "value2", "value3");

var queryStr = builder.Build();
queryStr.Trim()
Expand All @@ -278,17 +262,14 @@ public void Should_Use_NotIn_Filter_With_Tag_Prop()
}

[TestMethod]
public void Should_Use_NotIn_Filter_Inside_ExpressionFilter_Prop2()
public void Should_Use_NotIn_Filter_Inside_ExpressionFilter()
{
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.Where("prop1s")
.Equal("value")
.And("tenant1")
.NotIn("tag1", "tag2", "tag3")
.And("prop2")
.Equal("newValue");
.Where("prop1s").Equal("value")
.And("tenant1").NotIn("tag1", "tag2", "tag3")
.And("prop2").Equal("newValue");

var queryStr = builder.Build();

Expand All @@ -298,21 +279,31 @@ public void Should_Use_NotIn_Filter_Inside_ExpressionFilter_Prop2()
}

[TestMethod]
public void Should_Use_NotIn_Filter_At_Start_Of_ExpressionFilter_Prop2()
public void Should_Use_NotIn_Filter_At_Start_Of_ExpressionFilter()
{
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.Where("tenant1")
.NotIn("tag1", "tag2", "tag3")
.And("prop2")
.Equal("newValue");
.Where("tenant1").NotIn("tag1", "tag2", "tag3")
.And("prop2").Equal("newValue");

var queryStr = builder.Build();

queryStr.Trim()
.Should()
.Be("(tenant1 ne 'tag1' and tenant1 ne 'tag2' and tenant1 ne 'tag3') and prop2 eq 'newValue'");
}
[TestMethod]
public void Should_Use_NotIn_Filter_At_End_Of_ExpressionFilter()
{
var builder = new TableStorageQueryBuilder<PersonEntity>(new TagFilterExpression<PersonEntity>());

(builder.Query as TagFilterExpression<PersonEntity>)
.Where("tenant1").NotIn("tag1", "tag2", "tag3");
var queryStr = builder.Build();
queryStr.Trim()
.Should()
.Be("(tenant1 ne 'tag1' and tenant1 ne 'tag2' and tenant1 ne 'tag3')");
}
}
}

0 comments on commit 633cf66

Please sign in to comment.