/// <summary> /// Bind path segment's operation or operationImport's parameters. /// </summary> /// <param name="configuration">The ODataUriParserConfiguration.</param> /// <param name="functionOrOpertion">The function or operation.</param> /// <param name="segmentParameterTokens">The parameter tokens to be binded.</param> /// <returns>The binded semantic nodes.</returns> 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 (FunctionParameterToken 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 (KeyValuePair <IEdmOperationParameter, SingleValueNode> item in result) { SingleValueNode boundNode = item.Value; // ensure node type is compatible with parameter type. IEdmTypeReference 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); }
/// <summary> /// Promotes types of arguments to match signature if possible. /// </summary> /// <param name="signature">The signature to match the types to.</param> /// <param name="argumentNodes">The types to promote.</param> internal static void TypePromoteArguments(FunctionSignatureWithReturnType signature, List <QueryNode> argumentNodes) { // Convert all argument nodes to the best signature argument type Debug.Assert(signature.ArgumentTypes.Length == argumentNodes.Count, "The best signature match doesn't have the same number of arguments."); for (int i = 0; i < argumentNodes.Count; i++) { Debug.Assert(argumentNodes[i] is SingleValueNode, "We should have already verified that all arguments are single values."); SingleValueNode argumentNode = (SingleValueNode)argumentNodes[i]; IEdmTypeReference signatureArgumentType = signature.ArgumentTypes[i]; Debug.Assert(signatureArgumentType.IsODataPrimitiveTypeKind() || signatureArgumentType.IsODataEnumTypeKind(), "Only primitive or enum types should be able to get here."); argumentNodes[i] = MetadataBindingUtils.ConvertToTypeIfNeeded(argumentNode, signatureArgumentType); } }
/// <summary> /// Binds a unary operator token. /// </summary> /// <param name="unaryOperatorToken">The unary operator token to bind.</param> /// <returns>The bound unary operator token.</returns> internal QueryNode BindUnaryOperator(UnaryOperatorToken unaryOperatorToken) { ExceptionUtils.CheckArgumentNotNull(unaryOperatorToken, "unaryOperatorToken"); SingleValueNode operand = this.GetOperandFromToken(unaryOperatorToken); IEdmTypeReference typeReference = UnaryOperatorBinder.PromoteOperandType(operand, unaryOperatorToken.OperatorKind); Debug.Assert(typeReference == null || typeReference.IsODataPrimitiveTypeKind(), "Only primitive types should be able to get here."); operand = MetadataBindingUtils.ConvertToTypeIfNeeded(operand, typeReference); return(new UnaryOperatorNode(unaryOperatorToken.OperatorKind, operand)); }
/// <summary> /// Binds a key property value. /// </summary> /// <param name="namedValue">The named value to bind.</param> /// <param name="collectionItemEntityType">The type of a single item in a collection to apply the key value to.</param> /// <param name="keys">Dictionary of alias to keys.</param> /// <param name="keyPropertyValue">The bound key property value node.</param> /// <returns>The bound key property value node.</returns> private bool TryBindKeyPropertyValue(NamedValue namedValue, IEdmEntityType collectionItemEntityType, IDictionary <string, IEdmProperty> keys, out KeyPropertyValue keyPropertyValue) { // These are exception checks because the data comes directly from the potentially user specified tree. ExceptionUtils.CheckArgumentNotNull(namedValue, "namedValue"); ExceptionUtils.CheckArgumentNotNull(namedValue.Value, "namedValue.Value"); Debug.Assert(collectionItemEntityType != null, "collectionItemType != null"); IEdmProperty keyProperty = null; if (namedValue.Name == null) { foreach (IEdmProperty p in keys.Values) { if (keyProperty == null) { keyProperty = p; } else { throw new ODataException(ODataErrorStrings.MetadataBinder_UnnamedKeyValueOnTypeWithMultipleKeyProperties(collectionItemEntityType.FullTypeName())); } } } else { keyProperty = keys.SingleOrDefault(k => string.CompareOrdinal(k.Key, namedValue.Name) == 0).Value; if (keyProperty == null) { keyPropertyValue = null; return(false); } } IEdmTypeReference keyPropertyType = keyProperty.Type; SingleValueNode value = (SingleValueNode)this.keyValueBindMethod(namedValue.Value); // TODO: Check that the value is of primitive type Debug.Assert(keyPropertyType.IsODataPrimitiveTypeKind(), "The key's type must be primitive."); value = MetadataBindingUtils.ConvertToTypeIfNeeded(value, keyPropertyType); Debug.Assert(keyProperty != null, "keyProperty != null"); keyPropertyValue = new KeyPropertyValue() { KeyProperty = keyProperty, KeyValue = value }; return(true); }
/// <summary> /// Promote the left and right operand types /// </summary> /// <param name="binaryOperatorKind">the operator kind</param> /// <param name="left">the left operand</param> /// <param name="right">the right operand</param> /// <param name="facetsPromotionRules">Promotion rules for type facets.</param> internal static void PromoteOperandTypes(BinaryOperatorKind binaryOperatorKind, ref SingleValueNode left, ref SingleValueNode right, TypeFacetsPromotionRules facetsPromotionRules) { IEdmTypeReference leftType; IEdmTypeReference rightType; if (!TypePromotionUtils.PromoteOperandTypes(binaryOperatorKind, left, right, out leftType, out rightType, facetsPromotionRules)) { string leftTypeName = left.TypeReference == null ? "<null>" : left.TypeReference.FullName(); string rightTypeName = right.TypeReference == null ? "<null>" : right.TypeReference.FullName(); throw new ODataException(ODataErrorStrings.MetadataBinder_IncompatibleOperandsError(leftTypeName, rightTypeName, binaryOperatorKind)); } left = MetadataBindingUtils.ConvertToTypeIfNeeded(left, leftType); right = MetadataBindingUtils.ConvertToTypeIfNeeded(right, rightType); }