-
Notifications
You must be signed in to change notification settings - Fork 358
Fix cast in expand #2300
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
Fix cast in expand #2300
Changes from 11 commits
bed3398
5fba1dd
390b5eb
4dc02f2
e078e9c
baf500a
3bb2a12
b4cb609
6aeaa3c
ff060a1
b685d36
8d62b20
2228ef2
7f4ff99
6a4c552
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 | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -343,6 +343,27 @@ private SelectItem GenerateExpandItem(ExpandTermToken tokenIn) | |||||||||||||
| PathSegmentToken currentToken = tokenIn.PathToNavigationProp; | ||||||||||||||
|
|
||||||||||||||
| IEdmStructuredType currentLevelEntityType = this.EdmType; | ||||||||||||||
|
|
||||||||||||||
| // If we have a previous level binding with the last segment as a Type segment, | ||||||||||||||
| // The currentLevelEntityType should be the Type of the TypeSegment | ||||||||||||||
| // E.g /Orders?$expand=Customer/NS.VipCustomer($expand=Trips) | ||||||||||||||
| // If we are Binding the expanded property Trips, currentLevelEntityType should be the type of the VipCustomer | ||||||||||||||
| if (this.parsedSegments.Count > 0 && this.parsedSegments.Last() is TypeSegment) | ||||||||||||||
| { | ||||||||||||||
| IEdmType typeSegmentType = this.parsedSegments.Last().EdmType; | ||||||||||||||
KenitoInc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
|
|
||||||||||||||
| IEdmCollectionType collection = typeSegmentType as IEdmCollectionType; | ||||||||||||||
|
|
||||||||||||||
| if (collection != null) | ||||||||||||||
| { | ||||||||||||||
| currentLevelEntityType = (typeSegmentType as IEdmCollectionType).ElementType.Definition as IEdmStructuredType; | ||||||||||||||
KenitoInc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| } | ||||||||||||||
| else | ||||||||||||||
| { | ||||||||||||||
| currentLevelEntityType = typeSegmentType as IEdmStructuredType; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| List<ODataPathSegment> pathSoFar = new List<ODataPathSegment>(); | ||||||||||||||
| PathSegmentToken firstNonTypeToken = currentToken; | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -441,23 +462,25 @@ private SelectItem GenerateExpandItem(ExpandTermToken tokenIn) | |||||||||||||
|
|
||||||||||||||
| ODataExpandPath pathToNavProp = new ODataExpandPath(pathSoFar); | ||||||||||||||
|
|
||||||||||||||
| IEdmTypeReference elementTypeReference = hasDerivedTypeSegment ? derivedType.ToTypeReference() : null; | ||||||||||||||
|
Contributor
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. Out of curiosity, why does the
Contributor
Author
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. It's null since we can get it from the expanded property in these lines odata.net/src/Microsoft.OData.Core/UriParser/Binders/SelectExpandBinder.cs Lines 924 to 929 in 1452522
Member
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. I see that we are getting the type in SelectExpandBinder, but what is the contract with BindFilter, BindOrderby, etc? These private functions take an elementType which gets passed eventually to CreateBindingState where the logic is to fall back to the navigationSource, if it's not otherwise specified. But it's not clear in the various private methods that the elementType is nullable, and future code could make invalid assumptions about whether it may be null. If that private CreateBindingState method is only reached through these methods, would it be cleaner to compute the elementType from the targetNavigationSource here so it is never null in subsequent methods? Alternatively, maybe at least clarify in the description of the elementType parameter to the various methods (i.e., line 529) "The target element type if different from the type of the target navigation source." Logic is sound, I just want us to consider what is the cleaner/more intuitive contract for maintainability.
Contributor
Author
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. @mikepizzo I have updated the description. |
||||||||||||||
|
|
||||||||||||||
| // $apply | ||||||||||||||
| ApplyClause applyOption = BindApply(tokenIn.ApplyOptions, this.ResourcePathNavigationSource, targetNavigationSource); | ||||||||||||||
| ApplyClause applyOption = BindApply(tokenIn.ApplyOptions, this.ResourcePathNavigationSource, targetNavigationSource, elementTypeReference); | ||||||||||||||
|
|
||||||||||||||
| // $compute | ||||||||||||||
| ComputeClause computeOption = BindCompute(tokenIn.ComputeOption, this.ResourcePathNavigationSource, targetNavigationSource); | ||||||||||||||
| ComputeClause computeOption = BindCompute(tokenIn.ComputeOption, this.ResourcePathNavigationSource, targetNavigationSource, elementTypeReference); | ||||||||||||||
|
|
||||||||||||||
| var generatedProperties = GetGeneratedProperties(computeOption, applyOption); | ||||||||||||||
| bool collapsed = applyOption?.Transformations.Any(t => t.Kind == TransformationNodeKind.Aggregate || t.Kind == TransformationNodeKind.GroupBy) ?? false; | ||||||||||||||
|
|
||||||||||||||
| // $filter | ||||||||||||||
| FilterClause filterOption = BindFilter(tokenIn.FilterOption, this.ResourcePathNavigationSource, targetNavigationSource, null, generatedProperties, collapsed); | ||||||||||||||
| FilterClause filterOption = BindFilter(tokenIn.FilterOption, this.ResourcePathNavigationSource, targetNavigationSource, elementTypeReference, generatedProperties, collapsed); | ||||||||||||||
KenitoInc marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
|
||||||||||||||
| // $orderby | ||||||||||||||
| OrderByClause orderbyOption = BindOrderby(tokenIn.OrderByOptions, this.ResourcePathNavigationSource, targetNavigationSource, null, generatedProperties, collapsed); | ||||||||||||||
| OrderByClause orderbyOption = BindOrderby(tokenIn.OrderByOptions, this.ResourcePathNavigationSource, targetNavigationSource, elementTypeReference, generatedProperties, collapsed); | ||||||||||||||
|
|
||||||||||||||
| // $search | ||||||||||||||
| SearchClause searchOption = BindSearch(tokenIn.SearchOption, this.ResourcePathNavigationSource, targetNavigationSource, null); | ||||||||||||||
| SearchClause searchOption = BindSearch(tokenIn.SearchOption, this.ResourcePathNavigationSource, targetNavigationSource, elementTypeReference); | ||||||||||||||
|
|
||||||||||||||
| if (isRef) | ||||||||||||||
| { | ||||||||||||||
|
|
@@ -470,7 +493,7 @@ private SelectItem GenerateExpandItem(ExpandTermToken tokenIn) | |||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // $select & $expand | ||||||||||||||
| SelectExpandClause subSelectExpand = BindSelectExpand(tokenIn.ExpandOption, tokenIn.SelectOption, parsedPath, this.ResourcePathNavigationSource, targetNavigationSource, null, generatedProperties, collapsed); | ||||||||||||||
| SelectExpandClause subSelectExpand = BindSelectExpand(tokenIn.ExpandOption, tokenIn.SelectOption, parsedPath, this.ResourcePathNavigationSource, targetNavigationSource, elementTypeReference, generatedProperties, collapsed); | ||||||||||||||
|
|
||||||||||||||
| // $levels | ||||||||||||||
| LevelsClause levelsOption = ParseLevels(tokenIn.LevelsOption, currentLevelEntityType, currentNavProp); | ||||||||||||||
|
|
@@ -485,12 +508,13 @@ private SelectItem GenerateExpandItem(ExpandTermToken tokenIn) | |||||||||||||
| /// <param name="applyToken">The apply tokens to visit.</param> | ||||||||||||||
| /// <param name="resourcePathNavigationSource">The navigation source at the resource path.</param> | ||||||||||||||
| /// <param name="targetNavigationSource">The target navigation source at the current level.</param> | ||||||||||||||
| /// <param name="elementType">The target element type if different from the type of the target navigation source.</param> | ||||||||||||||
| /// <returns>The null or the built apply clause.</returns> | ||||||||||||||
| private ApplyClause BindApply(IEnumerable<QueryToken> applyToken, IEdmNavigationSource resourcePathNavigationSource, IEdmNavigationSource targetNavigationSource) | ||||||||||||||
| private ApplyClause BindApply(IEnumerable<QueryToken> applyToken, IEdmNavigationSource resourcePathNavigationSource, IEdmNavigationSource targetNavigationSource, IEdmTypeReference elementType = null) | ||||||||||||||
| { | ||||||||||||||
| if (applyToken != null && applyToken.Any()) | ||||||||||||||
| { | ||||||||||||||
| MetadataBinder binder = BuildNewMetadataBinder(this.Configuration, resourcePathNavigationSource, targetNavigationSource, null); | ||||||||||||||
| MetadataBinder binder = BuildNewMetadataBinder(this.Configuration, resourcePathNavigationSource, targetNavigationSource, elementType); | ||||||||||||||
| ApplyBinder applyBinder = new ApplyBinder(binder.Bind, binder.BindingState); | ||||||||||||||
| return applyBinder.BindApply(applyToken); | ||||||||||||||
| } | ||||||||||||||
|
|
@@ -504,7 +528,7 @@ private ApplyClause BindApply(IEnumerable<QueryToken> applyToken, IEdmNavigation | |||||||||||||
| /// <param name="computeToken">The compute token to visit.</param> | ||||||||||||||
| /// <param name="resourcePathNavigationSource">The navigation source at the resource path.</param> | ||||||||||||||
| /// <param name="targetNavigationSource">The target navigation source at the current level.</param> | ||||||||||||||
| /// <param name="elementType">The target element type.</param> | ||||||||||||||
| /// <param name="elementType">The target element type if different from the type of the target navigation source.</param> | ||||||||||||||
| /// <returns>The null or the built compute clause.</returns> | ||||||||||||||
| private ComputeClause BindCompute(ComputeToken computeToken, IEdmNavigationSource resourcePathNavigationSource, IEdmNavigationSource targetNavigationSource, IEdmTypeReference elementType = null) | ||||||||||||||
| { | ||||||||||||||
|
|
@@ -524,7 +548,7 @@ private ComputeClause BindCompute(ComputeToken computeToken, IEdmNavigationSourc | |||||||||||||
| /// <param name="filterToken">The filter token to visit.</param> | ||||||||||||||
| /// <param name="resourcePathNavigationSource">The navigation source at the resource path.</param> | ||||||||||||||
| /// <param name="targetNavigationSource">The target navigation source at the current level.</param> | ||||||||||||||
| /// <param name="elementType">The Edm element type.</param> | ||||||||||||||
| /// <param name="elementType">The target element type if different from the type of the target navigation source.</param> | ||||||||||||||
KenitoInc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| /// <param name="generatedProperties">The generated properties.</param> | ||||||||||||||
| /// <param name="collapsed">The collapsed boolean value.</param> | ||||||||||||||
| /// <returns>The null or the built filter clause.</returns> | ||||||||||||||
|
|
@@ -547,7 +571,7 @@ private FilterClause BindFilter(QueryToken filterToken, IEdmNavigationSource res | |||||||||||||
| /// <param name="orderByToken">The orderby token to visit.</param> | ||||||||||||||
| /// <param name="resourcePathNavigationSource">The navigation source at the resource path.</param> | ||||||||||||||
| /// <param name="targetNavigationSource">The target navigation source at the current level.</param> | ||||||||||||||
| /// <param name="elementType">The Edm element type.</param> | ||||||||||||||
| /// <param name="elementType">The target element type if different from the type of the target navigation source.</param> | ||||||||||||||
| /// <param name="generatedProperties">The generated properties.</param> | ||||||||||||||
| /// <param name="collapsed">The collapsed boolean value.</param> | ||||||||||||||
| /// <returns>The null or the built filter clause.</returns> | ||||||||||||||
|
|
@@ -571,7 +595,7 @@ private OrderByClause BindOrderby(IEnumerable<OrderByToken> orderByToken, IEdmNa | |||||||||||||
| /// <param name="searchToken">The search token to visit.</param> | ||||||||||||||
| /// <param name="resourcePathNavigationSource">The navigation source at the resource path.</param> | ||||||||||||||
| /// <param name="targetNavigationSource">The target navigation source at the current level.</param> | ||||||||||||||
| /// <param name="elementType">The Edm element type.</param> | ||||||||||||||
| /// <param name="elementType">The target element type if different from the type of the target navigation source.</param> | ||||||||||||||
| /// <returns>The null or the built search clause.</returns> | ||||||||||||||
| private SearchClause BindSearch(QueryToken searchToken, IEdmNavigationSource resourcePathNavigationSource, IEdmNavigationSource targetNavigationSource, IEdmTypeReference elementType) | ||||||||||||||
| { | ||||||||||||||
|
|
@@ -593,7 +617,7 @@ private SearchClause BindSearch(QueryToken searchToken, IEdmNavigationSource res | |||||||||||||
| /// <param name="segments">The parsed segments to visit.</param> | ||||||||||||||
| /// <param name="resourcePathNavigationSource">The navigation source at the resource path.</param> | ||||||||||||||
| /// <param name="targetNavigationSource">The target navigation source at the current level.</param> | ||||||||||||||
| /// <param name="elementType">The Edm element type.</param> | ||||||||||||||
| /// <param name="elementType">The target element type if different from the type of the target navigation source.</param> | ||||||||||||||
| /// <param name="generatedProperties">The generated properties.</param> | ||||||||||||||
| /// <param name="collapsed">The collapsed boolean value.</param> | ||||||||||||||
| /// <returns>The null or the built select and expand clause.</returns> | ||||||||||||||
|
|
@@ -659,8 +683,29 @@ private List<ODataPathSegment> ProcessSelectTokenPath(PathSegmentToken tokenIn) | |||||||||||||
| Debug.Assert(tokenIn != null, "tokenIn != null"); | ||||||||||||||
|
|
||||||||||||||
| List<ODataPathSegment> pathSoFar = new List<ODataPathSegment>(); | ||||||||||||||
|
|
||||||||||||||
| IEdmStructuredType currentLevelType = this.edmType; | ||||||||||||||
|
|
||||||||||||||
| // If we have a previous level binding with the last segment as a Type segment, | ||||||||||||||
| // The currentLevelEntityType should be the Type of the TypeSegment | ||||||||||||||
| // E.g /Orders?$expand=Customer/NS.VipCustomer($select=VipCustomerName) | ||||||||||||||
| // If we are Binding the selected property VipCustomerName, currentLevelEntityType should be the type of the VipCustomer | ||||||||||||||
| if (this.parsedSegments.Count > 0 && this.parsedSegments.Last() is TypeSegment) | ||||||||||||||
KenitoInc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
| { | ||||||||||||||
| IEdmType typeSegmentType = this.parsedSegments.Last().EdmType; | ||||||||||||||
|
|
||||||||||||||
| IEdmCollectionType collection = typeSegmentType as IEdmCollectionType; | ||||||||||||||
|
|
||||||||||||||
| if (collection != null) | ||||||||||||||
| { | ||||||||||||||
| currentLevelType = (typeSegmentType as IEdmCollectionType).ElementType.Definition as IEdmStructuredType; | ||||||||||||||
| } | ||||||||||||||
| else | ||||||||||||||
| { | ||||||||||||||
| currentLevelType = typeSegmentType as IEdmStructuredType; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // first, walk through all type segments in a row, converting them from tokens into segments. | ||||||||||||||
| if (tokenIn.IsNamespaceOrContainerQualified() && !UriParserHelper.IsAnnotation(tokenIn.Identifier)) | ||||||||||||||
| { | ||||||||||||||
|
|
||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.