/// <summary> /// Creates an <see cref="EntitySetNode"/> /// </summary> /// <param name="entitySet">The entity set this node represents</param> /// <exception cref="System.ArgumentNullException">Throws if the input entitySet is null.</exception> public EntitySetNode(IEdmEntitySet entitySet) { ExceptionUtils.CheckArgumentNotNull(entitySet, "entitySet"); this.entitySet = entitySet; this.entityType = new EdmEntityTypeReference(UriEdmHelpers.GetEntitySetElementType(this.EntitySet), false); this.collectionTypeReference = EdmCoreModel.GetCollection(this.entityType); }
/// <summary> /// Throws if the type is not related to the type of the given set. /// </summary> /// <param name="type">Type to check.</param> /// <param name="secondType">Second type, which should be related to the first type.</param> /// <param name="segmentName">The segment that is checking this.</param> internal static void ThrowIfTypesUnrelated(IEdmType type, IEdmType secondType, string segmentName) { if (!UriEdmHelpers.IsRelatedTo(type.AsElementType(), secondType)) { throw new ODataException(Strings.PathParser_TypeMustBeRelatedToSet(type, secondType, segmentName)); } }
private static void VerifyEnumVsStringFilterExpressionReverse(FilterClause filter) { var enumtypeRef = new EdmEnumTypeReference(UriEdmHelpers.FindEnumTypeFromModel(HardCodedTestModel.TestModel, "Fully.Qualified.Namespace.ColorPattern"), true); var bin = filter.Expression.ShouldBeBinaryOperatorNode(BinaryOperatorKind.Equal).And; bin.Right.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPet2PetColorPatternProperty()); bin.Left.ShouldBeEnumNode(new ODataEnumValue("2", enumtypeRef.ODataFullName())); }
public void GetNavigationPropertyFromExpandPathWithNavigationPropertySegmentReturnNavProperty() { var segment = new NavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp(), null); ODataPath odataPath = new ODataPath(segment); var result = UriEdmHelpers.GetNavigationPropertyFromExpandPath(odataPath); Assert.Same(segment.NavigationProperty, result); }
public void GetMostDerivedTypeFromPathWithMetadataSegmentAndNullReturnsType() { var segment = MetadataSegment.Instance; ODataPath odataPath = new ODataPath(segment); var result = UriEdmHelpers.GetMostDerivedTypeFromPath(odataPath, null); Assert.Null(result); }
public void GetMostDerivedTypeFromPathWithTypeSegmentAndNullReturnsNull() { var segment = new TypeSegment(HardCodedTestModel.GetHomeAddressType(), null); ODataPath odataPath = new ODataPath(segment); var result = UriEdmHelpers.GetMostDerivedTypeFromPath(odataPath, null); Assert.Null(result); }
/// <summary> /// Binds a DottedIdentifierToken and it's parent node (if needed). /// </summary> /// <param name="dottedIdentifierToken">Token to bind to metadata.</param> /// <param name="state">State of the Binding.</param> /// <returns>A bound node representing the cast.</returns> internal QueryNode BindDottedIdentifier(DottedIdentifierToken dottedIdentifierToken, BindingState state) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(dottedIdentifierToken, "castToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); QueryNode parent; IEdmType parentType; if (dottedIdentifierToken.NextToken == null) { parent = NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable); parentType = state.ImplicitRangeVariable.TypeReference.Definition; } else { parent = this.bindMethod(dottedIdentifierToken.NextToken); parentType = parent.GetEdmType(); } SingleEntityNode parentAsSingleValue = parent as SingleEntityNode; IEdmSchemaType childType = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier); IEdmEntityType childEntityType = childType as IEdmEntityType; if (childEntityType == null) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(bindMethod); QueryNode functionCallNode; if (functionCallBinder.TryBindDottedIdentifierAsFunctionCall(dottedIdentifierToken, parentAsSingleValue, state, out functionCallNode)) { return(functionCallNode); } else { throw new ODataException(ODataErrorStrings.CastBinder_ChildTypeIsNotEntity(dottedIdentifierToken.Identifier)); } } // Check whether childType is a derived type of the type of its parent node UriEdmHelpers.CheckRelatedTo(parentType, childType); EntityCollectionNode parentAsCollection = parent as EntityCollectionNode; if (parentAsCollection != null) { return(new EntityCollectionCastNode(parentAsCollection, childEntityType)); } // parent can be null for casts on the implicit parameter; this is OK if (parent == null) { return(new SingleEntityCastNode(null, childEntityType)); } Debug.Assert(parentAsSingleValue != null, "If parent of the cast node was not collection, it should be a single value."); return(new SingleEntityCastNode(parentAsSingleValue, childEntityType)); }
internal static bool TryBindIdentifier(string identifier, IEdmEnumTypeReference typeReference, IEdmModel modelWhenNoTypeReference, out QueryNode boundEnum) { boundEnum = null; string text = identifier; // parse the string, e.g., NS.Color'Green' // get type information, and also convert Green into an ODataEnumValue // find the first ', before that, it is namespace.type int indexOfSingleQuote = text.IndexOf('\''); if (indexOfSingleQuote < 0) { return(false); } string namespaceAndType = text.Substring(0, indexOfSingleQuote); Debug.Assert((typeReference == null) || (modelWhenNoTypeReference == null), "((typeReference == null) || (modelWhenNoTypeReference == null)"); // validate typeReference but allow type name not found in model for delayed throwing. if ((typeReference != null) && !string.Equals(namespaceAndType, typeReference.FullName())) { return(false); } // get the type IEdmEnumType enumType = typeReference != null ? (IEdmEnumType)typeReference.Definition : UriEdmHelpers.FindEnumTypeFromModel(modelWhenNoTypeReference, namespaceAndType); if (enumType == null) { return(false); } // now, find out the value UriParserHelper.TryRemovePrefix(namespaceAndType, ref text); UriParserHelper.TryRemoveQuotes(ref text); // parse string or int value to edm enum value string enumValueString = text; ODataEnumValue enumValue; if (!TryParseEnum(enumType, enumValueString, out enumValue)) { return(false); } // create an enum node, enclosing an odata enum value IEdmEnumTypeReference enumTypeReference = typeReference ?? new EdmEnumTypeReference(enumType, false); boundEnum = new ConstantNode(enumValue, identifier, enumTypeReference); return(true); }
public void GetNavigationPropertyFromExpandPathWithMetadataSegmentThrows() { var segment = MetadataSegment.Instance; ODataPath odataPath = new ODataPath(segment); Action uriParserHelpersAction = () => UriEdmHelpers.GetNavigationPropertyFromExpandPath(odataPath); uriParserHelpersAction.Throws <ODataException>( Strings.ExpandItemBinder_TypeSegmentNotFollowedByPath); }
public void GetNavigationPropertyFromExpandPathWithTypeSegmentThrows() { var segment = new TypeSegment(HardCodedTestModel.GetHomeAddressType(), null); ODataPath odataPath = new ODataPath(segment); Action uriParserHelpersAction = () => UriEdmHelpers.GetNavigationPropertyFromExpandPath(odataPath); uriParserHelpersAction.Throws <ODataException>( Strings.ExpandItemBinder_TypeSegmentNotFollowedByPath); }
/// <summary> /// Try to get an IEdmTypeReference for a given type as a string, returns null if none exists /// </summary> /// <param name="model">the model for validation</param> /// <param name="fullTypeName">the type name to find</param> /// <returns>an IEdmTypeReference for this type string.</returns> private static IEdmTypeReference TryGetTypeReference(IEdmModel model, string fullTypeName) { IEdmTypeReference typeReference = UriEdmHelpers.FindTypeFromModel(model, fullTypeName).ToTypeReference(); if (typeReference == null) { return(UriEdmHelpers.FindCollectionTypeFromModel(model, fullTypeName)); } return(typeReference); }
public void GetMostDerivedTypeFromPathWithTypeSegmentAndInheritedTypeReturnsInheritedType() { var segment = new TypeSegment(HardCodedTestModel.GetHomeAddressType(), null); ODataPath odataPath = new ODataPath(segment); TypeSegment typeSegment = odataPath.FirstSegment as TypeSegment; IEdmType type = typeSegment.EdmType; var result = UriEdmHelpers.GetMostDerivedTypeFromPath(odataPath, type); Assert.Equal(type, result); }
public void GetMostDerivedTypeFromPathWithTypeSegmentAndNotInheritedTypeReturnsNotInheritedType() { var segment = new TypeSegment(HardCodedTestModel.GetHomeAddressType(), null); ODataPath odataPath = new ODataPath(segment); IEdmEntityType astonishing = new EdmEntityType("AwesomeNamespace", "AstonishingEntity", null, false, false); IEdmEntityReferenceType entityRef = new EdmEntityReferenceType(astonishing); var result = UriEdmHelpers.GetMostDerivedTypeFromPath(odataPath, entityRef); Assert.Equal(entityRef, result); }
internal static bool TryBindIdentifier(string identifier, IEdmModel model, out QueryNode boundEnum) { boundEnum = null; string text = identifier; // parse the string, e.g., NS.Color'Green' // get type information, and also convert Green into an ODataEnumValue // find the first ', before that, it is namespace.type int indexOfSingleQuote = text.IndexOf('\''); if (indexOfSingleQuote < 0) { return(false); } string namespaceAndType = text.Substring(0, indexOfSingleQuote); // find the type from edm model IEdmEnumType enumType = UriEdmHelpers.FindEnumTypeFromModel(model, namespaceAndType); if (enumType == null) { return(false); } // now, find out the value UriPrimitiveTypeParser.TryRemovePrefix(namespaceAndType, ref text); UriPrimitiveTypeParser.TryRemoveQuotes(ref text); // parse string or int value to edm enum value string enumValueString = text; ODataEnumValue enumValue; enumType.TryParseEnum(enumValueString, out enumValue); if (enumValue == null) { return(false); } // create an enum node, enclosing an odata enum value EdmEnumTypeReference enumTypeReference = new EdmEnumTypeReference(enumType, false); boundEnum = new ConstantNode(enumValue, identifier, enumTypeReference); return(true); }
/// <summary> /// Parse from levelsOption token to LevelsClause. /// Negative value would be treated as max. /// </summary> /// <param name="levelsOption">The levelsOption for current expand.</param> /// <param name="sourceType">The type of current level navigation source.</param> /// <param name="property">Navigation property for current expand.</param> /// <returns>The LevelsClause parsed, null if levelsOption is null</returns> private LevelsClause ParseLevels(long?levelsOption, IEdmType sourceType, IEdmNavigationProperty property) { if (!levelsOption.HasValue) { return(null); } IEdmType relatedType = property.ToEntityType(); if (sourceType != null && relatedType != null && !UriEdmHelpers.IsRelatedTo(sourceType, relatedType)) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_LevelsNotAllowedOnIncompatibleRelatedType(property.Name, relatedType.FullTypeName(), sourceType.FullTypeName())); } return(new LevelsClause(levelsOption.Value < 0, levelsOption.Value)); }
public void TestEnumAsStringHas() { Uri unqualifiedEnumUri = new Uri("http://host/Pet2Set?$filter=PetColorPattern has 'Blue'"); var uriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, unqualifiedEnumUri) { Resolver = new StringAsEnumResolver() }; var filter = uriParser.ParseFilter(); var enumtypeRef = new EdmEnumTypeReference(UriEdmHelpers.FindEnumTypeFromModel(HardCodedTestModel.TestModel, "Fully.Qualified.Namespace.ColorPattern"), true); var bin = filter.Expression.ShouldBeBinaryOperatorNode(BinaryOperatorKind.Has); bin.Left.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPet2PetColorPatternProperty()); bin.Right.ShouldBeStringCompatibleEnumNode(enumtypeRef.EnumDefinition(), "2"); }
/// <summary> /// Try to get an IEdmTypeReference for a given type as a string, returns null if none exists /// </summary> /// <param name="model">the model for validation</param> /// <param name="fullTypeName">the type name to find</param> /// <param name="resolver">Resolver for this func.</param> /// <returns>an IEdmTypeReference for this type string.</returns> private static IEdmTypeReference TryGetTypeReference(IEdmModel model, string fullTypeName, ODataUriResolver resolver) { IEdmTypeReference typeReference = UriEdmHelpers.FindTypeFromModel(model, fullTypeName, resolver).ToTypeReference(); if (typeReference == null) { if (fullTypeName.StartsWith("Collection", StringComparison.Ordinal)) { string[] tokenizedString = fullTypeName.Split('('); string baseElementType = tokenizedString[1].Split(')')[0]; return(EdmCoreModel.GetCollection(UriEdmHelpers.FindTypeFromModel(model, baseElementType, resolver).ToTypeReference())); } else { return(null); } } return(typeReference); }
/// <summary> /// Follow any type segments on the path, stopping at the first segment that isn't a type token. /// </summary> /// <param name="firstTypeToken">the first type segment</param> /// <param name="model">the model these types are contained in.</param> /// <param name="maxDepth">the maximum recursive depth</param> /// <param name="currentLevelEntityType">the top level entity type, will be overwritten with the last entity type in the chain</param> /// <param name="firstNonTypeToken">the first non type token in the path</param> /// <returns>A path with type segments added to it.</returns> public static IEnumerable <ODataPathSegment> FollowTypeSegments(PathSegmentToken firstTypeToken, IEdmModel model, int maxDepth, ref IEdmEntityType currentLevelEntityType, out PathSegmentToken firstNonTypeToken) { ExceptionUtils.CheckArgumentNotNull(firstTypeToken, "firstTypeToken"); ExceptionUtils.CheckArgumentNotNull(model, "model"); if (!firstTypeToken.IsNamespaceOrContainerQualified()) { throw new ODataException(ODataErrorStrings.SelectExpandPathBinder_FollowNonTypeSegment(firstTypeToken.Identifier)); } int index = 0; List <ODataPathSegment> pathToReturn = new List <ODataPathSegment>(); PathSegmentToken currentToken = firstTypeToken; while (currentToken.IsNamespaceOrContainerQualified() && currentToken.NextToken != null) { IEdmEntityType previousLevelEntityType = currentLevelEntityType; currentLevelEntityType = UriEdmHelpers.FindTypeFromModel(model, currentToken.Identifier) as IEdmEntityType; if (currentLevelEntityType == null) { // TODO: fix this error message? throw new ODataException(ODataErrorStrings.ExpandItemBinder_CannotFindType(currentToken.Identifier)); } UriEdmHelpers.CheckRelatedTo(previousLevelEntityType, currentLevelEntityType); pathToReturn.Add(new TypeSegment(currentLevelEntityType, /*entitySet*/ null)); index++; currentToken = currentToken.NextToken; if (index >= maxDepth) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_PathTooDeep); } } firstNonTypeToken = currentToken; return(pathToReturn); }
/// <summary> /// Build a wildcard selection item /// </summary> /// <param name="tokenIn">the token to bind to a wildcard</param> /// <param name="model">the model to search for this wildcard</param> /// <param name="item">the new wildcard selection item, if we found one</param> /// <returns>true if we successfully bound to a wildcard, false otherwise</returns> public static bool TryBindAsWildcard(PathSegmentToken tokenIn, IEdmModel model, out SelectItem item) { bool isTypeToken = tokenIn.IsNamespaceOrContainerQualified(); bool wildcard = tokenIn.Identifier.EndsWith("*", StringComparison.Ordinal); IEdmEntityContainer container; if (isTypeToken && wildcard && UriEdmHelpers.TryGetEntityContainer(tokenIn.Identifier.Substring(0, tokenIn.Identifier.LastIndexOf('.')), model, out container)) { item = new ContainerQualifiedWildcardSelectItem(container); return(true); } if (tokenIn.Identifier == "*") { item = new WildcardSelectItem(); return(true); } item = null; return(false); }
private bool TryBindIdentifier(string identifier, IEnumerable <FunctionParameterToken> arguments, QueryNode parent, BindingState state, out QueryNode boundFunction) { boundFunction = null; IEdmType bindingType = null; var singleValueParent = parent as SingleValueNode; if (singleValueParent != null) { if (singleValueParent.TypeReference != null) { bindingType = singleValueParent.TypeReference.Definition; } } else { var collectionValueParent = parent as CollectionNode; if (collectionValueParent != null) { bindingType = collectionValueParent.CollectionType.Definition; } } if (!UriEdmHelpers.IsBindingTypeValid(bindingType)) { return(false); } IEdmFunctionImport functionImport; List <FunctionParameterToken> syntacticArguments = arguments == null ? new List <FunctionParameterToken>() : arguments.ToList(); if (!FunctionOverloadResolver.ResolveFunctionsFromList(identifier, syntacticArguments.Select(ar => ar.ParameterName).ToList(), bindingType, state.Model, out functionImport)) { return(false); } if (singleValueParent != null && singleValueParent.TypeReference == null) { // if the parent exists, but has no type information, then we're in open type land, and we // shouldn't go any farther. throw new ODataException(ODataErrorStrings.FunctionCallBinder_CallingFunctionOnOpenProperty(identifier)); } if (functionImport.IsSideEffecting) { return(false); } ICollection <FunctionParameterToken> parsedParameters; if (!FunctionParameterParser.TryParseFunctionParameters(syntacticArguments, state.Configuration, functionImport, out parsedParameters)) { return(false); } IEnumerable <QueryNode> boundArguments = parsedParameters.Select(p => this.bindMethod(p)); IEdmTypeReference returnType = functionImport.ReturnType; IEdmEntitySet returnSet = null; var singleEntityNode = parent as SingleEntityNode; if (singleEntityNode != null) { returnSet = functionImport.GetTargetEntitySet(singleEntityNode.EntitySet, state.Model); } if (returnType.IsEntity()) { boundFunction = new SingleEntityFunctionCallNode(identifier, new[] { functionImport }, boundArguments, (IEdmEntityTypeReference)returnType.Definition.ToTypeReference(), returnSet, parent); } else if (returnType.IsEntityCollection()) { IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType; boundFunction = new EntityCollectionFunctionCallNode(identifier, new[] { functionImport }, boundArguments, collectionTypeReference, returnSet, parent); } else if (returnType.IsCollection()) { IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType; boundFunction = new CollectionFunctionCallNode(identifier, new[] { functionImport }, boundArguments, collectionTypeReference, parent); } else { boundFunction = new SingleValueFunctionCallNode(identifier, new[] { functionImport }, boundArguments, returnType, parent); } return(true); }
/// <summary> /// Binds a DottedIdentifierToken and it's parent node (if needed). /// </summary> /// <param name="dottedIdentifierToken">Token to bind to metadata.</param> /// <param name="state">State of the Binding.</param> /// <returns>A bound node representing the cast.</returns> internal QueryNode BindDottedIdentifier(DottedIdentifierToken dottedIdentifierToken, BindingState state) { ExceptionUtils.CheckArgumentNotNull(dottedIdentifierToken, "castToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); QueryNode parent = null; IEdmType parentType = null; if (state.ImplicitRangeVariable != null) { if (dottedIdentifierToken.NextToken == null) { parent = NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable); parentType = state.ImplicitRangeVariable.TypeReference.Definition; } else { parent = this.bindMethod(dottedIdentifierToken.NextToken); parentType = parent.GetEdmType(); } } SingleEntityNode parentAsSingleValue = parent as SingleEntityNode; IEdmSchemaType childType = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier); IEdmStructuredType childStructuredType = childType as IEdmStructuredType; if (childStructuredType == null) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(bindMethod); QueryNode functionCallNode; if (functionCallBinder.TryBindDottedIdentifierAsFunctionCall(dottedIdentifierToken, parentAsSingleValue, state, out functionCallNode)) { return(functionCallNode); } else if ((!string.IsNullOrEmpty(dottedIdentifierToken.Identifier)) && (dottedIdentifierToken.Identifier[dottedIdentifierToken.Identifier.Length - 1] == '\'')) { // check if it is enum or not EnumBinder enumBinder = new EnumBinder(this.bindMethod); QueryNode enumNode; if (enumBinder.TryBindDottedIdentifierAsEnum(dottedIdentifierToken, parentAsSingleValue, state, out enumNode)) { return(enumNode); } else { throw new ODataException(ODataErrorStrings.Binder_IsNotValidEnumConstant(dottedIdentifierToken.Identifier)); } } else { IEdmTypeReference edmTypeReference = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier).ToTypeReference(); if (edmTypeReference is IEdmPrimitiveTypeReference || edmTypeReference is IEdmEnumTypeReference) { return(new ConstantNode(dottedIdentifierToken.Identifier, dottedIdentifierToken.Identifier)); } else { throw new ODataException(ODataErrorStrings.CastBinder_ChildTypeIsNotEntity(dottedIdentifierToken.Identifier)); } } } // Check whether childType is a derived type of the type of its parent node UriEdmHelpers.CheckRelatedTo(parentType, childType); IEdmEntityType childEntityType = childStructuredType as IEdmEntityType; if (childEntityType != null) { EntityCollectionNode parentAsCollection = parent as EntityCollectionNode; if (parentAsCollection != null) { return(new EntityCollectionCastNode(parentAsCollection, childEntityType)); } // parent can be null for casts on the implicit parameter; this is OK if (parent == null) { return(new SingleEntityCastNode(null, childEntityType)); } Debug.Assert(parentAsSingleValue != null, "If parent of the cast node was not collection, it should be a single value."); return(new SingleEntityCastNode(parentAsSingleValue, childEntityType)); } else { IEdmComplexType childComplexType = childStructuredType as IEdmComplexType; Debug.Assert(childComplexType != null, "If it is not entity type, it should be complex type"); CollectionPropertyAccessNode parentAsCollectionProperty = parent as CollectionPropertyAccessNode; if (parentAsCollectionProperty != null) { return(new CollectionPropertyCastNode(parentAsCollectionProperty, childComplexType)); } // parent can be null for casts on the implicit parameter; this is OK if (parent == null) { return(new SingleValueCastNode(null, childComplexType)); } SingleValueNode parentAsSingleValueNode = parent as SingleValueNode; Debug.Assert(parentAsSingleValueNode != null, "If parent of the cast node was not collection, it should be a single value."); return(new SingleValueCastNode(parentAsSingleValueNode, childComplexType)); } }
private bool TryBindIdentifier(string identifier, IEnumerable <FunctionParameterToken> arguments, QueryNode parent, BindingState state, out QueryNode boundFunction) { boundFunction = null; IEdmType bindingType = null; var singleValueParent = parent as SingleValueNode; if (singleValueParent != null) { if (singleValueParent.TypeReference != null) { bindingType = singleValueParent.TypeReference.Definition; } } else { var collectionValueParent = parent as CollectionNode; if (collectionValueParent != null) { bindingType = collectionValueParent.CollectionType.Definition; } } if (!UriEdmHelpers.IsBindingTypeValid(bindingType)) { return(false); } // All functions should be fully qualified, if they aren't they they aren't functions. // When using extension, there may be function call with unqualified name. So loose the restriction here. if (identifier.IndexOf(".", StringComparison.Ordinal) == -1 && this.Resolver.GetType() == typeof(ODataUriResolver)) { return(false); } IEdmOperation operation; List <FunctionParameterToken> syntacticArguments = arguments == null ? new List <FunctionParameterToken>() : arguments.ToList(); if (!FunctionOverloadResolver.ResolveOperationFromList(identifier, syntacticArguments.Select(ar => ar.ParameterName).ToList(), bindingType, state.Model, out operation, this.Resolver)) { // TODO: FunctionOverloadResolver.ResolveOperationFromList() looks up the function by parameter names, but it shouldn't ignore parameter types. (test case ParseFilter_AliasInFunction_PropertyAsValue_TypeMismatch should fail) return(false); } if (singleValueParent != null && singleValueParent.TypeReference == null) { // if the parent exists, but has no type information, then we're in open type land, and we // shouldn't go any farther. throw new ODataException(ODataErrorStrings.FunctionCallBinder_CallingFunctionOnOpenProperty(identifier)); } if (operation.IsAction()) { return(false); } IEdmFunction function = (IEdmFunction)operation; // TODO: $filter $orderby parameter expression which contains complex or collection should NOT be supported in this way // but should be parsed into token tree, and binded to node tree: parsedParameters.Select(p => this.bindMethod(p)); ICollection <FunctionParameterToken> parsedParameters = HandleComplexOrCollectionParameterValueIfExists(state.Configuration.Model, function, syntacticArguments, state.Configuration.Resolver.EnableCaseInsensitive); IEnumerable <QueryNode> boundArguments = parsedParameters.Select(p => this.bindMethod(p)); boundArguments = boundArguments.ToList(); // force enumerable to run : will immediately evaluate all this.bindMethod(p). IEdmTypeReference returnType = function.ReturnType; IEdmEntitySetBase returnSet = null; var singleEntityNode = parent as SingleEntityNode; if (singleEntityNode != null) { returnSet = function.GetTargetEntitySet(singleEntityNode.NavigationSource, state.Model); } string functionName = function.FullName(); if (returnType.IsEntity()) { boundFunction = new SingleEntityFunctionCallNode(functionName, new[] { function }, boundArguments, (IEdmEntityTypeReference)returnType.Definition.ToTypeReference(), returnSet, parent); } else if (returnType.IsEntityCollection()) { IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType; boundFunction = new EntityCollectionFunctionCallNode(functionName, new[] { function }, boundArguments, collectionTypeReference, returnSet, parent); } else if (returnType.IsCollection()) { IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType; boundFunction = new CollectionFunctionCallNode(functionName, new[] { function }, boundArguments, collectionTypeReference, parent); } else { boundFunction = new SingleValueFunctionCallNode(functionName, new[] { function }, boundArguments, returnType, parent); } return(true); }
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); }