-
Notifications
You must be signed in to change notification settings - Fork 351
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
Updated ODataUriParser to allow select and expand property names that… #2437
base: release-7.x
Are you sure you want to change the base?
Conversation
… conflict with reserved keywords
This PR has Quantification details
Why proper sizing of changes matters
Optimal pull request sizes drive a better predictable PR flow as they strike a
What can I do to optimize my changes
How to interpret the change counts in git diff output
Was this comment helpful? 👍 :ok_hand: :thumbsdown: (Email) |
@@ -81,7 +81,7 @@ internal sealed class SelectExpandParser | |||
|
|||
// Sets up our lexer. We don't turn useSemicolonDelimiter on since the parsing code for expand options, | |||
// which is the only thing that needs it, is in a different class that uses it's own lexer. | |||
this.lexer = clauseToParse != null ? new ExpressionLexer(clauseToParse, false /*moveToFirstToken*/, false /*useSemicolonDelimiter*/) : null; | |||
this.lexer = clauseToParse != null ? new ExpressionLexer(clauseToParse, false, false, false, false) : null; |
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.
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.
There's a lot going on here. For $filter=true eq true
, that's the same as just saying $filter=true
or not providing the filter at all. We interpret the "true" literal as a boolean expression, which as far as I can tell is in accordance with the standard. If there is a property named "true", the above is still accurate, but the client can disambiguate that they are referring to the property by using $it
, as in $filter=$it/true eq true
. The reality is that we also have a bug in that case as well. I talked with Mike yesterday and we decided that we would address the $filter
issue separately, since it implies a larger change (specifically, ExpressionLexer
applies semantics, but many query options require a syntax-only pass first; this syntax-only pass using ExpressionLexer
has issues across all of the query option implementations).
var parser = new ODataUriParser(model, new Uri("/foos?$select=null", UriKind.Relative)); | ||
var odataException = Assert.Throws<ODataException>(() => parser.ParseUri()); | ||
|
||
Assert.Equal("Could not find a property named 'null' on type 'foobar.foo'.", odataException.Message); |
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.
Should have another test where the type is defined as open -- in which case, no error should be returned.
@@ -108,6 +113,19 @@ internal ExpressionLexer(string expression, bool moveToFirstToken, bool useSemic | |||
/// <param name="useSemicolonDelimiter">If true, the lexer will tokenize based on semicolons as well.</param> | |||
/// <param name="parsingFunctionParameters">Whether the lexer is being used to parse function parameters. If true, will allow/recognize parameter aliases and typed nulls.</param> | |||
internal ExpressionLexer(string expression, bool moveToFirstToken, bool useSemicolonDelimiter, bool parsingFunctionParameters) |
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.
This is internal -- how many places do we call this existing method from? Would it be easier to add the parameter to the existing overload and explicitly pass "true", rather than define a new overload?
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.
Something unrelated --
I have in the past considered making the ExpressionLexer public and customizable.
/// <summary> | ||
/// Whether or not to interpret the semantics of a token that appears to be an identifier (i.e. consider if it is a keyword instead of an identifier) | ||
/// </summary> | ||
private readonly bool applySemanticsToIdentifiers; |
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.
Where are we setting this?
I think we should have this in the ODataUriParserSettings
.
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.
how can customer config this?
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.
Looks good to me. Left minor suggestions to improve legibility.
@@ -108,6 +113,19 @@ internal ExpressionLexer(string expression, bool moveToFirstToken, bool useSemic | |||
/// <param name="useSemicolonDelimiter">If true, the lexer will tokenize based on semicolons as well.</param> | |||
/// <param name="parsingFunctionParameters">Whether the lexer is being used to parse function parameters. If true, will allow/recognize parameter aliases and typed nulls.</param> | |||
internal ExpressionLexer(string expression, bool moveToFirstToken, bool useSemicolonDelimiter, bool parsingFunctionParameters) | |||
: this(expression, moveToFirstToken, useSemicolonDelimiter, parsingFunctionParameters, true) |
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.
For better legibility:
: this(expression, moveToFirstToken, useSemicolonDelimiter, parsingFunctionParameters, true) | |
: this(expression, moveToFirstToken, useSemicolonDelimiter, parsingFunctionParameters, applySemanticsToIdentifiers: true) | |
@@ -81,7 +81,7 @@ internal sealed class SelectExpandParser | |||
|
|||
// Sets up our lexer. We don't turn useSemicolonDelimiter on since the parsing code for expand options, | |||
// which is the only thing that needs it, is in a different class that uses it's own lexer. | |||
this.lexer = clauseToParse != null ? new ExpressionLexer(clauseToParse, false /*moveToFirstToken*/, false /*useSemicolonDelimiter*/) : null; | |||
this.lexer = clauseToParse != null ? new ExpressionLexer(clauseToParse, false, false, false, false) : null; |
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.
Hard to tell what all these false
params are for, suggestion to use named parameters in such cases:
this.lexer = clauseToParse != null ? new ExpressionLexer(clauseToParse, false, false, false, false) : null; | |
this.lexer = clauseToParse != null ? new ExpressionLexer(clauseToParse, moveToFirstToken: false, useSemicolonDelimiter: false, parsingFunctionParameters: false, applySemanticsToIdentifiers: false) : null; | |
} | ||
|
||
/// <summary> | ||
/// Selects a property named "null" when such a property doesn't exist on the entity |
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.
I think this comment should specify that this returns an error. On first reading, I assumed it actually does allow you to $select
a property name "null" without any issues, even when it doesn't exist.
} | ||
|
||
/// <summary> | ||
/// Expands a property named "null" when such a property doesn't exist on the entity |
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.
I think comment should mention that this results in an exception.
Others look good to me |
… conflict with reserved keywords
Issues
This pull request fixes #2410.
Description
The
SelectExpandParser
used by theODataUriParser
takes a two-pass approach to parsing the select and expand options. The first pass is intended to be syntactic only, while the second pass applies semantics. For code re-use, The syntactic pass leverages theExpressionLexer
. However,ExpressionLexer
applies some semantics while parsing when a perceived "identifier" token is reached. I have added a flag inExpressionLexer
to optionally disable these semantics, and updated theSelectExpandParser
to disable this behavior for its lexer.Checklist (Uncheck if it is not completed)
Additional work necessary
If documentation update is needed, please add "Docs Needed" label to the issue and provide details about the required document change in the issue.