public void BindFunctionForNullArgumentType() { this.functionCallBinder = new FunctionCallBinder(FakeBindMethods.BindMethodReturningANullLiteralConstantNode, this.binder.BindingState); var arguments = new List<QueryToken>() { new LiteralToken("ignored") }; var token = new FunctionCallToken("year", arguments); var result = functionCallBinder.BindFunctionCall(token); result.ShouldBeSingleValueFunctionCallQueryNode("year").And.Parameters.Single().ShouldBeConstantQueryNode<object>(null).And.TypeReference.Should().BeNull(); }
internal static List <OperationSegmentParameter> BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection <FunctionParameterToken> segmentParameterTokens) { // TODO: HandleComplexOrCollectionParameterValueIfExists is temp work around for single copmlex or colleciton type, it can't handle nested complex or collection value. ICollection <FunctionParameterToken> parametersParsed = FunctionCallBinder.HandleComplexOrCollectionParameterValueIfExists(configuration.Model, functionOrOpertion, segmentParameterTokens, configuration.Resolver.EnableCaseInsensitive, configuration.EnableUriTemplateParsing); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = null; state.RangeVariables.Clear(); MetadataBinder binder = new MetadataBinder(state); List <OperationSegmentParameter> boundParameters = new List <OperationSegmentParameter>(); IDictionary <string, SingleValueNode> input = new Dictionary <string, SingleValueNode>(StringComparer.Ordinal); foreach (var paraToken in parametersParsed) { // TODO: considering another better exception if (paraToken.ValueToken is EndPathToken) { throw new ODataException(Strings.MetadataBinder_ParameterNotInScope( string.Format(CultureInfo.InvariantCulture, "{0}={1}", paraToken.ParameterName, (paraToken.ValueToken as EndPathToken).Identifier))); } SingleValueNode boundNode = (SingleValueNode)binder.Bind(paraToken.ValueToken); if (!input.ContainsKey(paraToken.ParameterName)) { input.Add(paraToken.ParameterName, boundNode); } } IDictionary <IEdmOperationParameter, SingleValueNode> result = configuration.Resolver.ResolveOperationParameters(functionOrOpertion, input); foreach (var item in result) { SingleValueNode boundNode = item.Value; // ensure node type is compatible with parameter type. var sourceTypeReference = boundNode.GetEdmTypeReference(); bool sourceIsNullOrOpenType = (sourceTypeReference == null); if (!sourceIsNullOrOpenType) { // if the node has been rewritten, no further conversion is needed. if (!TryRewriteIntegralConstantNode(ref boundNode, item.Key.Type)) { boundNode = MetadataBindingUtils.ConvertToTypeIfNeeded(boundNode, item.Key.Type); } } OperationSegmentParameter boundParamer = new OperationSegmentParameter(item.Key.Name, boundNode); boundParameters.Add(boundParamer); } return(boundParameters); }
public void BindFunctionEmptyArguments() { // regression test for [UriParser] day() allowed. What does that mean? this.functionCallBinder = new FunctionCallBinder(FakeBindMethods.BindMethodReturnsNull, this.binder.BindingState); var token = new FunctionCallToken("day", new List<QueryToken>()); Action bindWithEmptyArguments = () => functionCallBinder.BindFunctionCall(token); FunctionSignatureWithReturnType[] signatures = FunctionCallBinder.GetBuiltInFunctionSignatures("day"); // to match the error message... blah bindWithEmptyArguments.ShouldThrow<ODataException>().WithMessage(ODataErrorStrings.MetadataBinder_NoApplicableFunctionFound( "day", BuiltInFunctions.BuildFunctionSignatureListDescription("day", signatures))); }
internal static List <OperationSegmentParameter> BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection <FunctionParameterToken> segmentParameterTokens) { // TODO: HandleComplexOrCollectionParameterValueIfExists is temp work around for single copmlex or colleciton type, it can't handle nested complex or collection value. ICollection <FunctionParameterToken> parametersParsed = FunctionCallBinder.HandleComplexOrCollectionParameterValueIfExists(configuration.Model, functionOrOpertion, segmentParameterTokens, configuration.EnableUriTemplateParsing); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = null; state.RangeVariables.Clear(); MetadataBinder binder = new MetadataBinder(state); List <OperationSegmentParameter> boundParameters = new List <OperationSegmentParameter>(); foreach (var paraToken in parametersParsed) { // TODO: considering another better exception if (paraToken.ValueToken is EndPathToken) { throw new ODataException(Strings.MetadataBinder_ParameterNotInScope( string.Format(CultureInfo.InvariantCulture, "{0}={1}", paraToken.ParameterName, (paraToken.ValueToken as EndPathToken).Identifier))); } SingleValueNode boundNode = (SingleValueNode)binder.Bind(paraToken.ValueToken); // ensure parameter name existis var functionParameter = functionOrOpertion.FindParameter(paraToken.ParameterName); if (functionParameter == null) { throw new ODataException(Strings.ODataParameterWriterCore_ParameterNameNotFoundInOperation(paraToken.ParameterName, functionOrOpertion.Name)); } // ensure node type is compatible with parameter type. var sourceTypeReference = boundNode.GetEdmTypeReference(); bool sourceIsNullOrOpenType = (sourceTypeReference == null); if (!sourceIsNullOrOpenType) { boundNode = MetadataBindingUtils.ConvertToTypeIfNeeded(boundNode, functionParameter.Type); } OperationSegmentParameter boundParamer = new OperationSegmentParameter(paraToken.ParameterName, boundNode); boundParameters.Add(boundParamer); } return(boundParameters); }
/// <summary> /// Binds a <see cref="InnerPathToken"/>. /// This includes more than just navigations - it includes complex property access and primitive collections. /// </summary> /// <param name="segmentToken">The segment token to bind.</param> /// <returns>The bound node.</returns> internal QueryNode BindInnerPathSegment(InnerPathToken segmentToken) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.bindMethod, state); // First we get the parent node QueryNode parent = this.DetermineParentNode(segmentToken, state); Debug.Assert(parent != null, "parent should never be null"); SingleValueNode singleValueParent = parent as SingleValueNode; if (singleValueParent == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return(boundFunction); } throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessSourceNotSingleValue(segmentToken.Identifier)); } // Using the parent and name of this token, we try to get the IEdmProperty it represents IEdmProperty property = BindProperty(singleValueParent.TypeReference, segmentToken.Identifier, this.Resolver); if (property == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return(boundFunction); } if (singleValueParent.TypeReference != null && !singleValueParent.TypeReference.Definition.IsOpenType()) { throw new ODataException( ODataErrorStrings.MetadataBinder_PropertyNotDeclared( parent.GetEdmTypeReference().FullName(), segmentToken.Identifier)); } return(new SingleValueOpenPropertyAccessNode(singleValueParent, segmentToken.Identifier)); } if (property.Type.IsODataComplexTypeKind()) { return(new SingleValuePropertyAccessNode(singleValueParent, property)); } // Note - this means nonentity collection (primitive or complex) if (property.Type.IsNonEntityCollectionType()) { return(new CollectionPropertyAccessNode(singleValueParent, property)); } IEdmNavigationProperty navigationProperty = property as IEdmNavigationProperty; if (navigationProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_IllegalSegmentType(property.Name)); } SingleEntityNode parentEntity = EnsureParentIsEntityForNavProp(singleValueParent); return(GetNavigationNode(navigationProperty, parentEntity, segmentToken.NamedValues, state, new KeyBinder(this.bindMethod))); }
/// <summary> /// Constructs a EndPathBinder object using the given function to bind parent token. /// </summary> /// <param name="bindMethod">Method to bind the EndPathToken's parent, if there is one.</param> /// <param name="state">State of the metadata binding.</param>am> /// <remarks> /// Make bindMethod of return type SingleValueQueryNode. /// </remarks> internal EndPathBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) : base(bindMethod, state) { this.functionCallBinder = new FunctionCallBinder(bindMethod, state); }
public void CannotBindArbitraryNumberOfOpenParametersWithCorrectNonOpenParameters() { this.functionCallBinder = new FunctionCallBinder(binder.Bind, this.binder.BindingState); var arguments = new List<QueryToken>() { new LiteralToken("datetime'1996-02-04'"), new LiteralToken("ignored") }; var token = new FunctionCallToken("day", arguments); Action bindWithEmptyArguments = () => functionCallBinder.BindFunctionCall(token); FunctionSignatureWithReturnType[] signatures = FunctionCallBinder.GetBuiltInFunctionSignatures("day"); // to match the error message... blah bindWithEmptyArguments.ShouldThrow<ODataException>().WithMessage(ODataErrorStrings.MetadataBinder_NoApplicableFunctionFound( "day", BuiltInFunctions.BuildFunctionSignatureListDescription("day", signatures))); }
private void ResetState() { BindingState state = new BindingState(this.configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet()); state.RangeVariables.Push(state.ImplicitRangeVariable); binder = new MetadataBinder(state); this.functionCallBinder = new FunctionCallBinder(binder.Bind, state); }
public void BindFunctionNullArgumentTypeArgumentCountMatchesFunctionSignature() { // regression test for: FunctionCallBinder should validate that the number of parameters matches for canonical function calls on open properties this.functionCallBinder = new FunctionCallBinder(FakeBindMethods.BindMethodReturningANullLiteralConstantNode, this.binder.BindingState); var arguments = new List<QueryToken>() { new LiteralToken("ignored"), new LiteralToken("ignored") }; var token = new FunctionCallToken("day", arguments); Action bindWithTooManyNonTypedArgs = () => functionCallBinder.BindFunctionCall(token); bindWithTooManyNonTypedArgs.ShouldThrow<ODataException>().WithMessage(ODataErrorStrings.FunctionCallBinder_CannotFindASuitableOverload("day", "2")); }
/// <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)); } }
/// <summary> /// Constructs a EndPathBinder object using the given function to bind parent token. /// </summary> /// <param name="bindMethod">Method to bind the EndPathToken's parent, if there is one.</param> /// <param name="state">State of the metadata binding.</param>am> /// <remarks> /// Make bindMethod of return type SingleValueQueryNode. /// </remarks> internal EndPathBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) : base(bindMethod, state) { this.functionCallBinder = new FunctionCallBinder(bindMethod, state); }
/// <summary> /// Binds a function call token. /// </summary> /// <param name="functionCallToken">The function call token to bind.</param> /// <returns>The bound function call token.</returns> protected virtual QueryNode BindFunctionCall(FunctionCallToken functionCallToken) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.Bind, this.BindingState); return(functionCallBinder.BindFunctionCall(functionCallToken)); }
/// <summary> /// Binds a function call token. /// </summary> /// <param name="functionCallToken">The function call token to bind.</param> /// <returns>The bound function call token.</returns> protected virtual QueryNode BindFunctionCall(FunctionCallToken functionCallToken) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.Bind, this.BindingState); return functionCallBinder.BindFunctionCall(functionCallToken); }
/// <summary> /// Binds a <see cref="InnerPathToken"/>. /// This includes more than just navigations - it includes complex property access and primitive collections. /// </summary> /// <param name="segmentToken">The segment token to bind.</param> /// <returns>The bound node.</returns> internal QueryNode BindInnerPathSegment(InnerPathToken segmentToken) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.bindMethod, state); // First we get the parent node QueryNode parent = this.DetermineParentNode(segmentToken, state); Debug.Assert(parent != null, "parent should never be null"); SingleValueNode singleValueParent = parent as SingleValueNode; if (singleValueParent == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return boundFunction; } throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessSourceNotSingleValue(segmentToken.Identifier)); } // Using the parent and name of this token, we try to get the IEdmProperty it represents IEdmProperty property = BindProperty(singleValueParent.TypeReference, segmentToken.Identifier, this.Resolver); if (property == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return boundFunction; } if (singleValueParent.TypeReference != null && !singleValueParent.TypeReference.Definition.IsOpenType()) { throw new ODataException( ODataErrorStrings.MetadataBinder_PropertyNotDeclared( parent.GetEdmTypeReference().FullName(), segmentToken.Identifier)); } return new SingleValueOpenPropertyAccessNode(singleValueParent, segmentToken.Identifier); } if (property.Type.IsODataComplexTypeKind()) { return new SingleValuePropertyAccessNode(singleValueParent, property); } // Note - this means nonentity collection (primitive or complex) if (property.Type.IsNonEntityCollectionType()) { return new CollectionPropertyAccessNode(singleValueParent, property); } IEdmNavigationProperty navigationProperty = property as IEdmNavigationProperty; if (navigationProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_IllegalSegmentType(property.Name)); } SingleEntityNode parentEntity = EnsureParentIsEntityForNavProp(singleValueParent); return GetNavigationNode(navigationProperty, parentEntity, segmentToken.NamedValues, state, new KeyBinder(this.bindMethod)); }
/// <summary> /// Constructs a EndPathBinder object using the given function to bind parent token. /// </summary> /// <param name="bindMethod">Method to bind the EndPathToken's parent, if there is one.</param> internal EndPathBinder(MetadataBinder.QueryTokenVisitor bindMethod) { this.bind = bindMethod; this.functionCallBinder = new FunctionCallBinder(bindMethod); }
/// <summary> /// Binds a DottedIdentifierToken and it's parent node (if needed). /// </summary> /// <param name="dottedIdentifierToken">Token to bind to metadata.</param> /// <returns>A bound node representing the cast.</returns> internal QueryNode BindDottedIdentifier(DottedIdentifierToken dottedIdentifierToken) { 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, this.Resolver); IEdmStructuredType childStructuredType = childType as IEdmStructuredType; if (childStructuredType == null) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(bindMethod, state); QueryNode functionCallNode; if (functionCallBinder.TryBindDottedIdentifierAsFunctionCall(dottedIdentifierToken, parent as SingleValueNode, out functionCallNode)) { return functionCallNode; } else if ((!string.IsNullOrEmpty(dottedIdentifierToken.Identifier)) && (dottedIdentifierToken.Identifier[dottedIdentifierToken.Identifier.Length - 1] == '\'')) { // check if it is enum or not 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, this.Resolver).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); } }