/// <summary> /// Verifies that CreateResourceReader, CreateResourceSetReader, CreateDeltaResourceSetReader or CreateDeltaReader can be called. /// </summary> /// <param name="navigationSource">The navigation source we are going to read resources for.</param> /// <param name="structuredType">The expected structured type for the resource/resource set to be read.</param> private void VerifyCanCreateODataReader(IEdmNavigationSource navigationSource, IEdmStructuredType structuredType) { Debug.Assert(navigationSource == null || structuredType != null, "If an navigation source is specified, the structured type must be specified as well."); // We require metadata information for reading requests. if (!this.ReadingResponse) { this.VerifyUserModel(); // TODO: check for entity only if (navigationSource == null && (structuredType != null && structuredType.IsODataEntityTypeKind())) { throw new ODataException(ODataErrorStrings.ODataJsonLightInputContext_NoEntitySetForRequest); } } // We only check that the base type of the entity set is assignable from the specified entity type. // If no resource set/resource type is specified in the API, we will read it from the context URI. IEdmEntityType entitySetElementType = this.EdmTypeResolver.GetElementType(navigationSource); if (navigationSource != null && structuredType != null && !structuredType.IsOrInheritsFrom(entitySetElementType)) { throw new ODataException(ODataErrorStrings.ODataJsonLightInputContext_EntityTypeMustBeCompatibleWithEntitySetBaseType(structuredType.FullTypeName(), entitySetElementType.FullName(), navigationSource.FullNavigationSourceName())); } }
/// <summary> /// Check whether the parent and child are properly related types /// </summary> /// <param name="parentType">the parent type</param> /// <param name="childType">the child type</param> /// <exception cref="ODataException">Throws if the two types are not related.</exception> public static void CheckRelatedTo(IEdmType parentType, IEdmType childType) { IEdmStructuredType childStructuredType = childType as IEdmStructuredType; if (!childStructuredType.IsOrInheritsFrom(parentType) && !parentType.IsOrInheritsFrom(childStructuredType)) { // If the parentType is an open property, parentType will be null and can't have an ODataFullName. string parentTypeName = (parentType != null) ? parentType.ODataFullName() : "<null>"; throw new ODataException(OData.Core.Strings.MetadataBinder_HierarchyNotFollowed(childStructuredType.FullTypeName(), parentTypeName)); } }
/// <summary> /// Process a <see cref="PathSegmentToken"/> following any type segments if necessary. /// </summary> /// <param name="tokenIn">the path token to process.</param> private List <ODataPathSegment> ProcessSelectTokenPath(PathSegmentToken tokenIn) { Debug.Assert(tokenIn != null, "tokenIn != null"); List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); IEdmStructuredType currentLevelType = this.edmType; // first, walk through all type segments in a row, converting them from tokens into segments. if (tokenIn.IsNamespaceOrContainerQualified() && !UriParserHelper.IsAnnotation(tokenIn.Identifier)) { PathSegmentToken firstNonTypeToken; pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(tokenIn, this.Model, this.Settings.SelectExpandLimit, this.configuration.Resolver, ref currentLevelType, out firstNonTypeToken)); Debug.Assert(firstNonTypeToken != null, "Did not get last token."); tokenIn = firstNonTypeToken as NonSystemToken; if (tokenIn == null) { throw new ODataException(ODataErrorStrings.SelectExpandBinder_SystemTokenInSelect(firstNonTypeToken.Identifier)); } } // next, create a segment for the first non-type segment in the path. ODataPathSegment lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(tokenIn, this.Model, currentLevelType, this.configuration.Resolver, this.state); // next, create an ODataPath and add the segments to it. if (lastSegment != null) { pathSoFar.Add(lastSegment); // try create a complex type property path. while (true) { // no need to go on if the current property is not of complex type or collection of complex type, // unless the segment is a primitive type cast or a property on an open complex property. currentLevelType = lastSegment.EdmType as IEdmStructuredType; IEdmCollectionType collectionType = lastSegment.EdmType as IEdmCollectionType; IEdmPrimitiveType primitiveType = lastSegment.EdmType as IEdmPrimitiveType; DynamicPathSegment dynamicPath = lastSegment as DynamicPathSegment; if ((currentLevelType == null || currentLevelType.TypeKind != EdmTypeKind.Complex) && (collectionType == null || collectionType.ElementType.TypeKind() != EdmTypeKind.Complex) && (primitiveType == null || primitiveType.TypeKind != EdmTypeKind.Primitive) && (dynamicPath == null || tokenIn.NextToken == null)) { break; } NonSystemToken nextToken = tokenIn.NextToken as NonSystemToken; if (nextToken == null) { break; } if (UriParserHelper.IsAnnotation(nextToken.Identifier)) { lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.Model, currentLevelType, this.configuration.Resolver, null); } else if (primitiveType == null && dynamicPath == null) { // This means last segment a collection of complex type, // current segment can only be type cast and cannot be property name. if (currentLevelType == null) { currentLevelType = collectionType.ElementType.Definition as IEdmStructuredType; } // If there is no collection type in the path yet, will try to bind property for the next token // first try bind the segment as property. lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.Model, currentLevelType, this.configuration.Resolver, null); } else { // determine whether we are looking at a type cast or a dynamic path segment. EdmPrimitiveTypeKind nextTypeKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(nextToken.Identifier); IEdmPrimitiveType castType = EdmCoreModel.Instance.GetPrimitiveType(nextTypeKind); if (castType != null) { lastSegment = new TypeSegment(castType, castType, null); } else if (dynamicPath != null) { lastSegment = new DynamicPathSegment(nextToken.Identifier); } else { throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect); } } // then try bind the segment as type cast. if (lastSegment == null) { IEdmStructuredType typeFromNextToken = UriEdmHelpers.FindTypeFromModel(this.Model, nextToken.Identifier, this.configuration.Resolver) as IEdmStructuredType; if (typeFromNextToken.IsOrInheritsFrom(currentLevelType)) { lastSegment = new TypeSegment(typeFromNextToken, /*entitySet*/ null); } } // type cast failed too. if (lastSegment == null) { break; } // try move to and add next path segment. tokenIn = nextToken; pathSoFar.Add(lastSegment); } } // non-navigation cases do not allow further segments in $select. if (tokenIn.NextToken != null) { throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect); } // Later, we can consider to create a "DynamicOperationSegment" to handle this. // But now, Let's throw exception. if (lastSegment == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_InvalidIdentifierInQueryOption(tokenIn.Identifier)); } // navigation property is not allowed to append sub path in the selection. NavigationPropertySegment navPropSegment = pathSoFar.LastOrDefault() as NavigationPropertySegment; if (navPropSegment != null && tokenIn.NextToken != null) { throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect); } return(pathSoFar); }
private void ProcessTokenAsPath(NonSystemToken tokenIn) { Debug.Assert(tokenIn != null, "tokenIn != null"); List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); IEdmStructuredType currentLevelType = this.edmType; // first, walk through all type segments in a row, converting them from tokens into segments. if (tokenIn.IsNamespaceOrContainerQualified()) { PathSegmentToken firstNonTypeToken; pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(tokenIn, this.model, this.maxDepth, this.resolver, ref currentLevelType, out firstNonTypeToken)); Debug.Assert(firstNonTypeToken != null, "Did not get last token."); tokenIn = firstNonTypeToken as NonSystemToken; if (tokenIn == null) { throw new ODataException(ODataErrorStrings.SelectPropertyVisitor_SystemTokenInSelect(firstNonTypeToken.Identifier)); } } // next, create a segment for the first non-type segment in the path. ODataPathSegment lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(tokenIn, this.model, currentLevelType, resolver); // next, create an ODataPath and add the segments to it. if (lastSegment != null) { pathSoFar.Add(lastSegment); // try create a complex type property path. while (true) { // no need to go on if the current property is not of complex type. currentLevelType = lastSegment.EdmType as IEdmStructuredType; if (currentLevelType == null || currentLevelType.TypeKind != EdmTypeKind.Complex) { break; } NonSystemToken nextToken = tokenIn.NextToken as NonSystemToken; if (nextToken == null) { break; } // first try bind the segment as property. lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.model, currentLevelType, resolver); // then try bind the segment as type cast. if (lastSegment == null) { IEdmStructuredType typeFromNextToken = UriEdmHelpers.FindTypeFromModel(this.model, nextToken.Identifier, this.resolver) as IEdmStructuredType; if (typeFromNextToken.IsOrInheritsFrom(currentLevelType)) { lastSegment = new TypeSegment(typeFromNextToken, /*entitySet*/ null); } } // type cast failed too. if (lastSegment == null) { break; } // try move to and add next path segment. tokenIn = nextToken; pathSoFar.Add(lastSegment); } } ODataSelectPath selectedPath = new ODataSelectPath(pathSoFar); var selectionItem = new PathSelectItem(selectedPath); // non-navigation cases do not allow further segments in $select. if (tokenIn.NextToken != null) { throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect); } // if the selected item is a nav prop, then see if its already there before we add it. NavigationPropertySegment trailingNavPropSegment = selectionItem.SelectedPath.LastSegment as NavigationPropertySegment; if (trailingNavPropSegment != null) { if (this.expandClauseToDecorate.SelectedItems.Any(x => x is PathSelectItem && ((PathSelectItem)x).SelectedPath.Equals(selectedPath))) { return; } } this.expandClauseToDecorate.AddToSelectedItems(selectionItem); }
private void ProcessTokenAsPath(NonSystemToken tokenIn) { Debug.Assert(tokenIn != null, "tokenIn != null"); List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); IEdmStructuredType currentLevelType = this.edmType; // first, walk through all type segments in a row, converting them from tokens into segments. if (tokenIn.IsNamespaceOrContainerQualified() && !UriParserHelper.IsAnnotation(tokenIn.Identifier)) { PathSegmentToken firstNonTypeToken; pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(tokenIn, this.model, this.maxDepth, this.resolver, ref currentLevelType, out firstNonTypeToken)); Debug.Assert(firstNonTypeToken != null, "Did not get last token."); tokenIn = firstNonTypeToken as NonSystemToken; if (tokenIn == null) { throw new ODataException(ODataErrorStrings.SelectPropertyVisitor_SystemTokenInSelect(firstNonTypeToken.Identifier)); } } // next, create a segment for the first non-type segment in the path. ODataPathSegment lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(tokenIn, this.model, currentLevelType, resolver, this.state); // next, create an ODataPath and add the segments to it. if (lastSegment != null) { pathSoFar.Add(lastSegment); // try create a complex type property path. while (true) { // no need to go on if the current property is not of complex type or collection of complex type, // unless the segment is a primitive type cast or a property on an open complex property. currentLevelType = lastSegment.EdmType as IEdmStructuredType; IEdmCollectionType collectionType = lastSegment.EdmType as IEdmCollectionType; IEdmPrimitiveType primitiveType = lastSegment.EdmType as IEdmPrimitiveType; DynamicPathSegment dynamicPath = lastSegment as DynamicPathSegment; if ((currentLevelType == null || currentLevelType.TypeKind != EdmTypeKind.Complex) && (collectionType == null || collectionType.ElementType.TypeKind() != EdmTypeKind.Complex) && (primitiveType == null || primitiveType.TypeKind != EdmTypeKind.Primitive) && (dynamicPath == null || tokenIn.NextToken == null)) { break; } NonSystemToken nextToken = tokenIn.NextToken as NonSystemToken; if (nextToken == null) { break; } if (UriParserHelper.IsAnnotation(nextToken.Identifier)) { lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.model, currentLevelType, resolver, null); } else if (primitiveType == null && dynamicPath == null) { // This means last segment a collection of complex type, // current segment can only be type cast and cannot be property name. if (currentLevelType == null) { currentLevelType = collectionType.ElementType.Definition as IEdmStructuredType; } // If there is no collection type in the path yet, will try to bind property for the next token // first try bind the segment as property. lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.model, currentLevelType, resolver, null); } else { // determine whether we are looking at a type cast or a dynamic path segment. EdmPrimitiveTypeKind nextTypeKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(nextToken.Identifier); IEdmPrimitiveType castType = EdmCoreModel.Instance.GetPrimitiveType(nextTypeKind); if (castType != null) { lastSegment = new TypeSegment(castType, castType, null); } else if (dynamicPath != null) { lastSegment = new DynamicPathSegment(nextToken.Identifier); } else { throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect); } } // then try bind the segment as type cast. if (lastSegment == null) { IEdmStructuredType typeFromNextToken = UriEdmHelpers.FindTypeFromModel(this.model, nextToken.Identifier, this.resolver) as IEdmStructuredType; if (typeFromNextToken.IsOrInheritsFrom(currentLevelType)) { lastSegment = new TypeSegment(typeFromNextToken, /*entitySet*/ null); } } // type cast failed too. if (lastSegment == null) { break; } // try move to and add next path segment. tokenIn = nextToken; pathSoFar.Add(lastSegment); } } ODataSelectPath selectedPath = new ODataSelectPath(pathSoFar); var selectionItem = new PathSelectItem(selectedPath); // non-navigation cases do not allow further segments in $select. if (tokenIn.NextToken != null) { throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect); } // if the selected item is a nav prop, then see if its already there before we add it. NavigationPropertySegment trailingNavPropSegment = selectionItem.SelectedPath.LastSegment as NavigationPropertySegment; if (trailingNavPropSegment != null) { if (this.expandClauseToDecorate.SelectedItems.Any(x => x is PathSelectItem && ((PathSelectItem)x).SelectedPath.Equals(selectedPath))) { return; } } this.expandClauseToDecorate.AddToSelectedItems(selectionItem); }