-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tables: Query support for dictionary entities and CreateFilter #12366
Changes from all commits
f3d0a2d
c944e90
819280c
fe112d7
98cd3b1
0945050
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq.Expressions; | ||
|
||
namespace Azure.Data.Tables.Queryable | ||
{ | ||
public static class TableClientExtensions | ||
{ | ||
/// <summary> | ||
/// Creates an Odata filter query string from the provided expression. | ||
/// </summary> | ||
/// <typeparam name="T">The type of the entity being queried. Typically this will be derrived from <see cref="TableEntity"/> or <see cref="Dictionary{String, Object}"/>.</typeparam> | ||
/// <param name="client">The <see cref="TableClient"/>.</param> | ||
/// <param name="filter">A filter expresssion.</param> | ||
/// <returns>The string representation of the filter expression.</returns> | ||
public static string CreateFilter<T>(this TableClient client, Expression<Func<T, bool>> filter) => client.Bind(filter); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,19 @@ internal override Expression Visit(Expression exp) | |
return result; | ||
} | ||
|
||
internal override Expression VisitMethodCall(MethodCallExpression m) | ||
{ | ||
if (m.Method == ReflectionUtil.DictionaryGetItemMethodInfo && m.Arguments.Count == 1 && m.Arguments[0] is ConstantExpression ce) | ||
{ | ||
_builder.Append(ce.Value as string); | ||
} | ||
else | ||
{ | ||
return base.VisitMethodCall(m); | ||
} | ||
|
||
return m; | ||
} | ||
|
||
internal override Expression VisitMemberAccess(MemberExpression m) | ||
{ | ||
|
@@ -155,9 +168,17 @@ private void VisitOperand(Expression e) | |
{ | ||
if (e is BinaryExpression || e is UnaryExpression) | ||
{ | ||
_builder.Append(UriHelper.LEFTPAREN); | ||
Visit(e); | ||
_builder.Append(UriHelper.RIGHTPAREN); | ||
if (e is UnaryExpression unary && unary.NodeType == ExpressionType.TypeAs) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a functional benefit in dropping the parenthesis for casts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case the parens are not useful. The cast is only needed for the comparison to satisfy the compiler in that all dictionary entries are |
||
{ | ||
Visit(unary.Operand); | ||
} | ||
else | ||
{ | ||
_builder.Append(UriHelper.LEFTPAREN); | ||
Visit(e); | ||
_builder.Append(UriHelper.RIGHTPAREN); | ||
} | ||
|
||
} | ||
else | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Collections.Generic; | ||
using System.Reflection; | ||
|
||
namespace Azure.Data.Tables.Queryable | ||
{ | ||
internal static class ReflectionUtil | ||
{ | ||
internal static MethodInfo DictionaryGetItemMethodInfo { get; } | ||
|
||
static ReflectionUtil() | ||
{ | ||
DictionaryGetItemMethodInfo = typeof(IDictionary<string, object>).GetMethod("get_Item"); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at ExpressionNormalizer and ExpressionWriter I wonder if we really need both or if they can be merged into one with additional benefit of avoiding creating of more Expression nodes just to throw them away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some cases the normalizer is simplifying the expression to be written by the writer. I'd like to do an optimization pass at some point to address issues like this and others.