Skip to content

Commit

Permalink
make:
Browse files Browse the repository at this point in the history
http://localhost:5168/odata/schools?$filter=Branches/any(a: a/City eq 'Redmond') work
  • Loading branch information
xuzhg committed Feb 7, 2023
1 parent c688742 commit 26e01ca
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 8 deletions.
2 changes: 1 addition & 1 deletion OData/OData.WebApi/Extensions/DbExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static void MakeSureDbCreated(this WebApplication app)
var context = services.GetRequiredService<ApplicationDbContext>();

// uncomment the following to delete it
context.Database.EnsureDeleted();
//context.Database.EnsureDeleted();

context.Database.EnsureCreated();
}
Expand Down
56 changes: 49 additions & 7 deletions OData/OData.WebApi/Extensions/SchoolStudentFilterBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ namespace OData.WebApi.Extensions;

public class SchoolStudentFilterBinder : FilterBinder
{
/*
/*JSON column array query seems not supported. See details at: https://github.com/OData/AspNetCoreOData/issues/816
// and: https://github.com/dotnet/efcore/issues/30132
public override Expression BindCountNode(CountNode node, QueryBinderContext context)
{
// $filter=Branches/$count eq 1
Expand Down Expand Up @@ -70,12 +71,12 @@ public override Expression BindCountNode(CountNode node, QueryBinderContext cont

public override Expression BindAnyNode(AnyNode anyNode, QueryBinderContext context)
{
// ?$filter=ContactEmails/any(a: a eq 'help@mercury.com')
Expression source = context.CurrentParameter;

if (anyNode.Source is CollectionPropertyAccessNode collectionPropertyAccessNode &&
string.Equals(collectionPropertyAccessNode.Property.Name, "ContactEmails", StringComparison.OrdinalIgnoreCase))
// ?$filter = ContactEmails / any(a: a eq 'help@mercury.com')
{
Expression source = context.CurrentParameter;

// $it.Emails
PropertyInfo emailsProperty = context.ElementClrType.GetProperty("Emails");
Expression propertyValue = Expression.Property(source, emailsProperty);
Expand All @@ -85,7 +86,7 @@ public override Expression BindAnyNode(AnyNode anyNode, QueryBinderContext conte
BinaryOperatorNode bodyOperator = anyNode.Body as BinaryOperatorNode;
if (bodyOperator != null)
{
// Here, i just process the 'Eq'
// Here, i just process the 'Eq' for simplicity. You can add more.
if (bodyOperator.OperatorKind == BinaryOperatorKind.Equal &&
bodyOperator.Right is ConstantNode constNode)
{
Expand All @@ -96,13 +97,52 @@ public override Expression BindAnyNode(AnyNode anyNode, QueryBinderContext conte
if (constExp != null)
{
// string.Contains
MethodInfo containsMethodInfo = GetContainsMethodInfo();
MethodInfo containsMethodInfo = ConstainsMethodInfo;

// $it.Emails.Contains("....")
return Expression.Call(propertyValue, containsMethodInfo, constExp);
}
}

if (anyNode.Source is CollectionComplexNode collectionComplexNode &&
string.Equals(collectionComplexNode.Property.Name, "Branches", StringComparison.OrdinalIgnoreCase))
{
// ?$filter=Branches/any(a: a/City eq 'Kallangur')

// $it.Branches
PropertyInfo branchesProperty = context.ElementClrType.GetProperty("Branches"); // Branches is JSON string from DB
Expression propertyValue = Expression.Property(source, branchesProperty);

Expression constExp = null;
if (anyNode.Body is BinaryOperatorNode bodyOperatorNode)
{
// It could be anything in the body, here, i just process the binary operator
// Here, i just process the 'Eq' for simplicity. You can add more.
if (bodyOperatorNode.OperatorKind == BinaryOperatorKind.Equal &&
bodyOperatorNode.Right is ConstantNode constNode)
{
// Since JSON array query doesn't fully support, Here's the trick:
// Let's search the combination: "City":"Kallangur"
if (bodyOperatorNode.Left is SingleValuePropertyAccessNode properyAccessNode)
{
string propertyName = properyAccessNode.Property.Name;
string constNodeValue = constNode.Value.ToString();

constExp = Expression.Constant($"\"{propertyName}\":\"{constNodeValue}\"");
}
}
}

if (constExp != null)
{
// string.Contains
MethodInfo containsMethodInfo = ConstainsMethodInfo;

// $it.Branches.Contains("....")
return Expression.Call(propertyValue, containsMethodInfo, constExp);
}
}

return base.BindAnyNode(anyNode, context);
}

Expand All @@ -126,7 +166,7 @@ public override Expression BindInNode(InNode inNode, QueryBinderContext context)
Expression propertyValue = Expression.Property(source, emailsProperty);

// string.Contains
MethodInfo containsMethodInfo = GetContainsMethodInfo();
MethodInfo containsMethodInfo = ConstainsMethodInfo;

//
return Expression.Call(propertyValue, containsMethodInfo, singleValue);
Expand All @@ -136,6 +176,8 @@ public override Expression BindInNode(InNode inNode, QueryBinderContext context)
return base.BindInNode(inNode, context);
}

private static MethodInfo ConstainsMethodInfo = GetContainsMethodInfo();

private static MethodInfo GetContainsMethodInfo()
{
// If you want to ignore case, fetch the other overload of "Contains"
Expand Down
Binary file added OData/OData.WebApi/app.db-shm
Binary file not shown.
Empty file added OData/OData.WebApi/app.db-wal
Empty file.

0 comments on commit 26e01ca

Please sign in to comment.