/// <summary> /// Override this method if you want to visit each query node. /// </summary> /// <remarks> /// This method is intended to be called from method overrides in subclasses. This method also supports unit-testing scenarios and is not intended to be called from user code. /// Call the Validate method to validate a <see cref="FilterQueryOption"/> instance. /// </remarks> /// <param name="node"></param> /// <param name="settings"></param> public virtual void ValidateQueryNode(QueryNode node, ODataValidationSettings settings) { // Recursion guard to avoid stack overflows RuntimeHelpers.EnsureSufficientExecutionStack(); SingleValueNode singleNode = node as SingleValueNode; CollectionNode collectionNode = node as CollectionNode; IncrementNodeCount(settings); if (singleNode != null) { ValidateSingleValueNode(singleNode, settings); } else if (collectionNode != null) { ValidateCollectionNode(collectionNode, settings); } }
private static Stack <SingleValueNode> ReversePropertyPath(SingleValueNode node) { var result = new Stack <SingleValueNode>(); do { result.Push(node); if (node.Kind == QueryNodeKind.SingleValuePropertyAccess) { node = ((SingleValuePropertyAccessNode)node).Source; } else if (node.Kind == QueryNodeKind.SingleNavigationNode) { node = ((SingleNavigationNode)node).NavigationSource as SingleValueNode; } }while (node != null && IsPropertyNode(node)); return(result); }
private static string GetNodePropertyName(SingleValueNode property) { if (property.Kind == QueryNodeKind.SingleValuePropertyAccess) { return(((SingleValuePropertyAccessNode)property).Property.Name); } else if (property.Kind == QueryNodeKind.SingleComplexNode) { return(((SingleComplexNode)property).Property.Name); } else if (property.Kind == QueryNodeKind.SingleNavigationNode) { return(((SingleNavigationNode)property).NavigationProperty.Name); } else { throw new NotSupportedException(); } }
/// <summary> /// Parse expression into syntaxs token tree, and bind it into semantics node tree. /// </summary> /// <param name="bindingState">The BindingState.</param> /// <param name="aliasValueExpression">The alias value's expression text.</param> /// <returns>The semantcs node of the expression text.</returns> private SingleValueNode ParseAndBindParameterAliasValueExpression(BindingState bindingState, string aliasValueExpression) { // Get the syntactic representation of the filter expression // TODO: change Settings.FilterLimit to ParameterAliasValueLimit UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(bindingState.Configuration.Settings.FilterLimit); QueryToken aliasValueToken = expressionParser.ParseExpressionText(aliasValueExpression); // Get the semantic node, and check for SingleValueNode QueryNode aliasValueNode = this.bindMethod(aliasValueToken); SingleValueNode result = aliasValueNode as SingleValueNode; if (result == null) { // TODO: add string resource throw new ODataException("ODataErrorStrings.MetadataBinder_ParameterAliasValueExpressionNotSingleValue"); } return(result); }
/// <summary> /// Retrieves the type reference associated to a segment. /// </summary> /// <param name="segment">The node to retrive the type reference from.</param> /// <returns>The Type reference of the node (item type reference for collections).</returns> internal static IEdmTypeReference GetEdmTypeReference(this QueryNode segment) { DebugUtils.CheckNoExternalCallers(); SingleValueNode singleNode = segment as SingleValueNode; if (singleNode != null) { return(singleNode.TypeReference); } CollectionNode collectionNode = segment as CollectionNode; if (collectionNode != null) { return(collectionNode.ItemType); } return(null); }
private string BuildWhereClause(SingleValueNode node) { string result = string.Empty; var operatorNode = node as BinaryOperatorNode; if (operatorNode == null) { if (node is SingleValueFunctionCallNode operatorNode2 && operatorNode2.Parameters.ToList()[0] is SingleValuePropertyAccessNode prop && operatorNode2.Parameters.ToList()[1] is ConstantNode val) { return($"{prop.Property.Name} LIKE '%{val.LiteralText.Trim(new char[] { (char)39 })}%' "); } else { return(result); } }
/// <summary> /// Retrieves <see cref="EdmClrProperty" /> from the given <see cref="SingleValueNode" />. /// </summary> /// <param name="node">The node to get the property from.</param> protected EdmClrProperty GetProperty(SingleValueNode node) { if (!(node is SingleValuePropertyAccessNode propertyAccessNode)) { throw new ODataException($"The '{node.GetType().Name}' node is not supported."); } if (!(propertyAccessNode.Property is EdmClrProperty property)) { throw new ODataException($"The '{propertyAccessNode.Property.GetType().Name}' property is not supported."); } if (!(propertyAccessNode.Source is ResourceRangeVariableReferenceNode)) { throw new ODataException($"Nested properties are not supported."); } return(property); }
/// <summary> /// Bind the expression of the LambdaToken /// </summary> /// <param name="queryToken">the expression token</param> /// <returns>the bound expression node</returns> private SingleValueNode BindExpressionToken(QueryToken queryToken) { SingleValueNode expression = this.bindMethod(queryToken) as SingleValueNode; if (expression == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_AnyAllExpressionNotSingleValue); } // type reference is allowed to be null for open properties. IEdmTypeReference expressionTypeReference = expression.GetEdmTypeReference(); if (expressionTypeReference != null && !expressionTypeReference.AsPrimitive().IsBoolean()) { throw new ODataException(ODataErrorStrings.MetadataBinder_AnyAllExpressionNotSingleValue); } return(expression); }
/// <summary> /// Binds a an end path token into a PropertyAccessToken, OpenPropertyToken, or FunctionCallToken. /// </summary> /// <param name="endPathToken">The property access token to bind.</param> /// <returns>A Query node representing this endpath token, bound to metadata.</returns> internal QueryNode BindEndPath(EndPathToken endPathToken) { ExceptionUtils.CheckArgumentNotNull(endPathToken, "EndPathToken"); ExceptionUtils.CheckArgumentStringNotNullOrEmpty(endPathToken.Identifier, "EndPathToken.Identifier"); // Set the parent (get the parent type, so you can check whether the Identifier inside EndPathToken really is legit offshoot of the parent type) QueryNode parent = this.DetermineParentNode(endPathToken); QueryNode boundFunction; SingleValueNode singleValueParent = parent as SingleValueNode; if (singleValueParent == null) { if (functionCallBinder.TryBindEndPathAsFunctionCall(endPathToken, parent, state, out boundFunction)) { return(boundFunction); } throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessSourceNotSingleValue(endPathToken.Identifier)); } // Now that we have the parent type, can find its corresponding EDM type IEdmStructuredTypeReference structuredParentType = singleValueParent.TypeReference == null ? null : singleValueParent.TypeReference.AsStructuredOrNull(); IEdmProperty property = structuredParentType == null ? null : this.Resolver.ResolveProperty(structuredParentType.StructuredDefinition(), endPathToken.Identifier); if (property != null) { return(GeneratePropertyAccessQueryNode(singleValueParent, property)); } if (functionCallBinder.TryBindEndPathAsFunctionCall(endPathToken, singleValueParent, state, out boundFunction)) { return(boundFunction); } return(GeneratePropertyAccessQueryForOpenType(endPathToken, singleValueParent)); }
private Expression BindAccessor(SingleValueNode node) { switch (node.Kind) { case QueryNodeKind.ResourceRangeVariableReference: return(this._lambdaParameter.Type.IsGenericType && this._lambdaParameter.Type.GetGenericTypeDefinition() == typeof(FlatteningWrapper <>) ? (Expression)Expression.Property(this._lambdaParameter, "Source") : this._lambdaParameter); case QueryNodeKind.SingleValuePropertyAccess: var propAccessNode = node as SingleValuePropertyAccessNode; return(CreatePropertyAccessExpression(BindAccessor(propAccessNode.Source), propAccessNode.Property, GetFullPropertyPath(propAccessNode))); case QueryNodeKind.SingleComplexNode: var singleComplexNode = node as SingleComplexNode; return(CreatePropertyAccessExpression(BindAccessor(singleComplexNode.Source), singleComplexNode.Property, GetFullPropertyPath(singleComplexNode))); case QueryNodeKind.SingleValueOpenPropertyAccess: var openNode = node as SingleValueOpenPropertyAccessNode; return(GetFlattenedPropertyExpression(openNode.Name) ?? Expression.Property(BindAccessor(openNode.Source), openNode.Name)); case QueryNodeKind.None: case QueryNodeKind.SingleNavigationNode: var navNode = node as SingleNavigationNode; return(CreatePropertyAccessExpression(BindAccessor(navNode.Source), navNode.NavigationProperty)); case QueryNodeKind.BinaryOperator: var binaryNode = node as BinaryOperatorNode; var leftExpression = BindAccessor(binaryNode.Left); var rightExpression = BindAccessor(binaryNode.Right); return(CreateBinaryExpression(binaryNode.OperatorKind, leftExpression, rightExpression, liftToNull: true)); case QueryNodeKind.Convert: var convertNode = node as ConvertNode; return(CreateConvertExpression(convertNode, BindAccessor(convertNode.Source))); default: throw Error.NotSupported(SRResources.QueryNodeBindingNotSupported, node.Kind, typeof(AggregationBinder).Name); } }
private static Query ProcessBinaryOperatorNode(Query query, BinaryOperatorNode binaryOperatorNode) { switch (binaryOperatorNode.OperatorKind) { case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.LessThanOrEqual: SingleValueNode singleValueNodeLeft = binaryOperatorNode.Left; SingleValueNode singleValueNodeRight = binaryOperatorNode.Right; if (singleValueNodeLeft.Kind == QueryNodeKind.Constant && singleValueNodeRight.Kind == QueryNodeKind.SingleValuePropertyAccess) { SingleValuePropertyAccessNode singleValuePropertyAccessNode = (SingleValuePropertyAccessNode)singleValueNodeRight; ConstantNode constantNode = (ConstantNode)singleValueNodeLeft; return(query.Where(singleValuePropertyAccessNode.Property.Name, _binaryOperatorKindToSymbolDictionary[binaryOperatorNode.OperatorKind], constantNode.Value)); } else if (singleValueNodeLeft.Kind == QueryNodeKind.SingleValuePropertyAccess && singleValueNodeRight.Kind == QueryNodeKind.Constant) { SingleValuePropertyAccessNode singleValuePropertyAccessNode = (SingleValuePropertyAccessNode)singleValueNodeLeft; ConstantNode constantNode = (ConstantNode)singleValueNodeRight; return(query.Where(singleValuePropertyAccessNode.Property.Name, _binaryOperatorKindToSymbolDictionary[binaryOperatorNode.OperatorKind], constantNode.Value)); } else { throw new NotImplementedException(); } } return(query); }
static string Bind(QueryNode node) { CollectionNode collectionNode = node as CollectionNode; SingleValueNode singleValueNode = node as SingleValueNode; if (singleValueNode != null) { switch (singleValueNode.Kind) { //case QueryNodeKind.: // return BindRangeVariable((node as EntityRangeVariableReferenceNode).RangeVariable); case QueryNodeKind.SingleValuePropertyAccess: return(BindPropertyAccessQueryNode(node as SingleValuePropertyAccessNode)); default: return(string.Empty); } } return(string.Empty); }
/// <summary> /// Checks that all arguments are SingleValueNodes /// </summary> /// <param name="functionName">The name of the function the arguments are from.</param> /// <param name="argumentNodes">The arguments to validate.</param> /// <returns>SingleValueNode array</returns> internal static SingleValueNode[] ValidateArgumentsAreSingleValue(string functionName, List <QueryNode> argumentNodes) { ExceptionUtils.CheckArgumentNotNull(functionName, "functionCallToken"); ExceptionUtils.CheckArgumentNotNull(argumentNodes, "argumentNodes"); // Right now all functions take a single value for all arguments SingleValueNode[] ret = new SingleValueNode[argumentNodes.Count]; for (int i = 0; i < argumentNodes.Count; i++) { SingleValueNode argumentNode = argumentNodes[i] as SingleValueNode; if (argumentNode == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_FunctionArgumentNotSingleValue(functionName)); } ret[i] = argumentNode; } return(ret); }
/// <summary> /// Retrieves type associated to a segment. /// </summary> /// <param name="segment">The node to retrive the type from.</param> /// <returns>The type of the node, or item type for collections.</returns> internal static IEdmType GetEdmType(this QueryNode segment) { SingleValueNode singleNode = segment as SingleValueNode; if (singleNode != null) { IEdmTypeReference typeRef = singleNode.TypeReference; return((typeRef != null) ? typeRef.Definition : null); } CollectionNode collectionNode = segment as CollectionNode; if (collectionNode != null) { IEdmTypeReference typeRef = collectionNode.ItemType; return((typeRef != null) ? typeRef.Definition : null); } return(null); }
/// <summary> /// Append OData filtering to the FilterExpression. /// </summary> /// <param name="criteria">Filter container for the QueryExpression.</param> /// <param name="expression">An expression containing OData filtering details.</param> private void UpdateCriteriaFromExpression(FilterExpression criteria, SingleValueNode expression) { switch (expression.Kind) { case QueryNodeKind.BinaryOperator: UpdateCriteriaFromBinaryExpression(criteria, (BinaryOperatorNode)expression); break; case QueryNodeKind.Convert: UpdateCriteriaFromExpression(criteria, ((ConvertNode)expression).Source); break; case QueryNodeKind.SingleValueFunctionCall: UpdateCriteriaFromSingleValueFunctionCall(criteria, (SingleValueFunctionCallNode)expression); break; default: throw new NotImplementedException(String.Format("Unsupported expression kind: \'{0}\'.", expression.Kind)); } }
private void ValidateSingleValueNode(SingleValueNode node, ValidationSettings settings) { switch (node.Kind) { case QueryNodeKind.Convert: ValidateQueryNode((node as ConvertNode).Source, settings); break; case QueryNodeKind.BinaryOperator: ValidateBinaryOperatorNode(node as BinaryOperatorNode, settings); break; case QueryNodeKind.UnaryOperator: ValidateUnaryOperatorNode(node as UnaryOperatorNode, settings); break; case QueryNodeKind.SingleValuePropertyAccess: ValidateQueryNode((node as SingleValuePropertyAccessNode).Source, settings); break; case QueryNodeKind.SingleValueFunctionCall: ValidateSingleValueFunctionCallNode(node as SingleValueFunctionCallNode, settings); break; case QueryNodeKind.Any: ValidateAnyNode(node as AnyNode, settings); break; case QueryNodeKind.SingleResourceCast: ValidateQueryNode((node as SingleResourceCastNode).Source, settings); break; case QueryNodeKind.All: ValidateAllNode(node as AllNode, settings); break; case QueryNodeKind.SingleResourceFunctionCall: ValidateSingleResourceFunctionCallNode(node as SingleResourceFunctionCallNode, settings); break; } }
/// <summary> /// Checks that all arguments are SingleValueNodes /// </summary> /// <param name="functionName">The name of the function the arguments are from.</param> /// <param name="argumentNodes">The arguments to validate.</param> /// <returns>Returns the types of the arguments provided.</returns> internal static IEdmTypeReference[] EnsureArgumentsAreSingleValue(string functionName, List <QueryNode> argumentNodes) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(functionName, "functionCallToken"); ExceptionUtils.CheckArgumentNotNull(argumentNodes, "argumentNodes"); // Right now all functions take a single value for all arguments IEdmTypeReference[] argumentTypes = new IEdmTypeReference[argumentNodes.Count]; for (int i = 0; i < argumentNodes.Count; i++) { SingleValueNode argumentNode = argumentNodes[i] as SingleValueNode; if (argumentNode == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_FunctionArgumentNotSingleValue(functionName)); } argumentTypes[i] = argumentNode.TypeReference; } return(argumentTypes); }
public static BinaryOperatorNode CreateFilterExpression(SingleValueNode singleValueNode, IEnumerable <KeyValuePair <IEdmStructuralProperty, Object?> > keys) { BinaryOperatorNode?compositeNode = null; foreach (KeyValuePair <IEdmStructuralProperty, Object?> keyValue in keys) { var left = new SingleValuePropertyAccessNode(singleValueNode, keyValue.Key); var right = new ConstantNode(keyValue.Value, ODataUriUtils.ConvertToUriLiteral(keyValue.Value, ODataVersion.V4)); var node = new BinaryOperatorNode(BinaryOperatorKind.Equal, left, right); if (compositeNode == null) { compositeNode = node; } else { compositeNode = new BinaryOperatorNode(BinaryOperatorKind.And, compositeNode, node); } } return(compositeNode ?? throw new InvalidOperationException("Parameter keys is empty collection")); }
public override void PromoteBinaryOperandTypes( BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { if (binaryOperatorKind == BinaryOperatorKind.Multiply && leftNode.TypeReference != null && leftNode.TypeReference.IsString() && rightNode.TypeReference != null && rightNode.TypeReference.IsInt32()) { // The result type should be Edm.String, as it could be nullable or not, we just took the left // node's type reference. typeReference = leftNode.TypeReference; return; } // fallback base.PromoteBinaryOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode, out typeReference); }
internal static BinaryOperatorNode CreateFilterExpression(SingleValueNode singleValueNode, IEnumerable <KeyValuePair <IEdmStructuralProperty, Object> > keys) { BinaryOperatorNode compositeNode = null; foreach (KeyValuePair <IEdmStructuralProperty, Object> keyValue in keys) { var left = new SingleValuePropertyAccessNode(singleValueNode, keyValue.Key); var right = new ConstantNode(keyValue.Value, ODataUriUtils.ConvertToUriLiteral(keyValue.Value, ODataVersion.V4)); var node = new BinaryOperatorNode(BinaryOperatorKind.Equal, left, right); if (compositeNode == null) { compositeNode = node; } else { compositeNode = new BinaryOperatorNode(BinaryOperatorKind.And, compositeNode, node); } } return(compositeNode); }
/// <summary> /// Binds a <see cref="QueryNode"/> to create a LINQ <see cref="Expression"/> that represents the semantics /// of the <see cref="QueryNode"/>. /// </summary> /// <param name="node">The node to bind.</param> /// <returns>The LINQ <see cref="Expression"/> created.</returns> public override Expression Bind(QueryNode node) { // Recursion guard to avoid stack overflows RuntimeHelpers.EnsureSufficientExecutionStack(); CollectionNode collectionNode = node as CollectionNode; SingleValueNode singleValueNode = node as SingleValueNode; if (collectionNode != null) { return(BindCollectionNode(collectionNode)); } else if (singleValueNode != null) { return(BindSingleValueNode(singleValueNode)); } else { throw Error.NotSupported(SRResources.QueryNodeBindingNotSupported, node.Kind, typeof(FilterBinder).Name); } }
internal Expression GetTuplePropertyByAliasName(Expression source, SingleValueNode singleValueNode) { String aliasName = GetAliasName(singleValueNode); int groupCount = 0; for (int i = 0; i < _aggProperties.Count; i++) { if (_aggProperties[i].IsGroup) { groupCount++; } if (String.CompareOrdinal(_aggProperties[i].Name, aliasName) == 0) { PropertyInfo propertyInfo; int itemIndex; if (_aggProperties[i].IsGroup) { propertyInfo = source.Type.GetProperty("Item1") !; source = Expression.Property(source, propertyInfo); itemIndex = groupCount; for (; itemIndex > 7; itemIndex -= 7) { propertyInfo = source.Type.GetProperty("Rest") !; source = Expression.Property(source, propertyInfo); } } else { itemIndex = i - groupCount + 2; } String propertyName = "Item" + itemIndex.ToString(CultureInfo.InvariantCulture); propertyInfo = source.Type.GetProperty(propertyName) !; return(Expression.Property(source, propertyInfo)); } } throw new InvalidOperationException("Property " + aliasName + " not found in " + source.Type.FullName); }
public static void TryNodeValue(SingleValueNode node, IDictionary <string, object> values) { if (node is BinaryOperatorNode) { var bon = (BinaryOperatorNode)node; var left = bon.Left; var right = bon.Right; if (left is ConvertNode) { TryNodeValue(((ConvertNode)left).Source, values); } if (left is BinaryOperatorNode) { TryNodeValue(left, values); } if (right is ConvertNode) { TryNodeValue(((ConvertNode)right).Source, values); } if (right is BinaryOperatorNode) { TryNodeValue(right, values); } if (left is SingleValuePropertyAccessNode && right is ConstantNode) { var p = (SingleValuePropertyAccessNode)left; if (bon.OperatorKind == BinaryOperatorKind.Equal) { var value = ((ConstantNode)right).Value; values.Add(p.Property.Name, value); } } } }
internal static SingleValueNode TranslateParameterAlias( SingleValueNode node, IDictionary <string, SingleValueNode> parameterAliasNodes) { if (node == null) { throw Error.ArgumentNull("node"); } if (parameterAliasNodes == null) { throw Error.ArgumentNull("parameterAliasNodes"); } ParameterAliasNode parameterAliasNode = node as ParameterAliasNode; if (parameterAliasNode == null) { return(node); } SingleValueNode singleValueNode; if (parameterAliasNodes.TryGetValue(parameterAliasNode.Alias, out singleValueNode) && singleValueNode != null) { if (singleValueNode is ParameterAliasNode) { singleValueNode = TranslateParameterAlias(singleValueNode, parameterAliasNodes); } return(singleValueNode); } // Parameter alias value is assumed to be null if it is not found. // Do not need to translate the parameter alias node from the query string // because this method only deals with the parameter alias node mapping from ODL parser. return(null); }
/// <summary> /// Apply $filter parameter to query. /// </summary> /// <param name="query"> /// The OData aware query. /// </param> /// <param name="filterText"> /// The $filter parameter text. /// </param> /// <param name="entitySetName"> /// The entity set name. /// </param> /// <typeparam name="T"> /// The query type param /// </typeparam> /// <returns> /// The <see cref="ODataQuery{T}"/> query with applied filter parameter. /// </returns> /// <exception cref="ArgumentNullException"> /// Argument Null Exception /// </exception> public static ODataQuery <T> Filter <T>(this ODataQuery <T> query, string filterText, string entitySetName = null) { if (query == null) { throw new ArgumentNullException(nameof(query)); } if (filterText == null) { throw new ArgumentNullException(nameof(filterText)); } IEdmModel edmModel = query.EdmModel; ODataQueryOptionParser queryOptionParser = GetParser( query, entitySetName, new Dictionary <string, string> { { "$filter", filterText } }); ODataSettings settings = query.ServiceProvider.GetRequiredService <ODataSettings>(); FilterClause filterClause = queryOptionParser.ParseFilter(); SingleValueNode filterExpression = filterClause.Expression.Accept( new ParameterAliasNodeTranslator(queryOptionParser.ParameterAliasNodes)) as SingleValueNode; filterExpression = filterExpression ?? new ConstantNode(null); filterClause = new FilterClause(filterExpression, filterClause.RangeVariable); Contract.Assert(filterClause != null); var validator = new FilterQueryValidator(settings.DefaultQuerySettings); validator.Validate(filterClause, settings.ValidationSettings, edmModel); Expression filter = FilterBinder.Bind(query, filterClause, typeof(T), query.ServiceProvider); var result = ExpressionHelpers.Where(query, filter, typeof(T)); return(new ODataQuery <T>(result, query.ServiceProvider)); }
/// <summary> /// Promote the left and right operand types, supports enum property and string constant scenario. /// </summary> /// <param name="binaryOperatorKind">the operator kind</param> /// <param name="leftNode">the left operand</param> /// <param name="rightNode">the right operand</param> /// <param name="typeReference">type reference for the result BinaryOperatorNode.</param> public override void PromoteBinaryOperandTypes( BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { typeReference = null; if (leftNode.TypeReference != null && rightNode.TypeReference != null) { if ((leftNode.TypeReference.IsEnum()) && (rightNode.TypeReference.IsString()) && rightNode is ConstantNode) { string text = ((ConstantNode)rightNode).Value as string; ODataEnumValue val; IEdmTypeReference typeRef = leftNode.TypeReference; if (TryParseEnum(typeRef.Definition as IEdmEnumType, text, out val)) { rightNode = new ConstantNode(val, text, typeRef); return; } } else if ((rightNode.TypeReference.IsEnum()) && (leftNode.TypeReference.IsString()) && leftNode is ConstantNode) { string text = ((ConstantNode)leftNode).Value as string; ODataEnumValue val; IEdmTypeReference typeRef = rightNode.TypeReference; if (TryParseEnum(typeRef.Definition as IEdmEnumType, text, out val)) { leftNode = new ConstantNode(val, text, typeRef); return; } } } // fallback base.PromoteBinaryOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode, out typeReference); }
private static Expression GetOrderByCall(this Expression expression, OrderByClause orderByClause) { const string OrderBy = "OrderBy"; const string OrderByDescending = "OrderByDescending"; return(orderByClause.ThenBy == null ? GetMethodCall() : GetMethodCall().GetThenByCall(orderByClause.ThenBy)); Expression GetMethodCall() { SingleValueNode orderByNode = orderByClause.Expression; switch (orderByNode) { case CountNode countNode: return(expression.GetOrderByCountCall ( countNode.GetPropertyPath(), orderByClause.Direction == OrderByDirection.Ascending ? OrderBy : OrderByDescending, orderByClause.RangeVariable.Name )); default: SingleValuePropertyAccessNode propertyNode = (SingleValuePropertyAccessNode)orderByNode; return(expression.GetOrderByCall ( propertyNode.GetPropertyPath(), orderByClause.Direction == OrderByDirection.Ascending ? OrderBy : OrderByDescending, orderByClause.RangeVariable.Name )); } } }
internal static string RestorePropertyPath(SingleValueNode expression) { if (expression == null) { return(String.Empty); } string propertyName = String.Empty; SingleValueNode source = null; var accessNode = expression as SingleValuePropertyAccessNode; if (accessNode != null) { propertyName = accessNode.Property.Name; source = accessNode.Source; } else { var complexNode = expression as SingleComplexNode; if (complexNode != null) { propertyName = complexNode.Property.Name; source = complexNode.Source; } } var parentPath = RestorePropertyPath(source); if (String.IsNullOrEmpty(parentPath)) { return(propertyName); } else { return(String.Format(CultureInfo.CurrentCulture, "{0}/{1}", parentPath, propertyName)); } }
private bool IsLeafNode(SingleValueNode node) { BinaryOperatorNode expression; if (node.Kind == QueryNodeKind.Convert) { var convertNode = node as ConvertNode; expression = (convertNode.Source as BinaryOperatorNode); } else if (node.Kind == QueryNodeKind.BinaryOperator) { expression = node as BinaryOperatorNode; } else { return(false); } var leftNode = expression.Left; var rightNode = expression.Right; return(leftNode is SingleValuePropertyAccessNode && rightNode is ConstantNode); }
internal string GetFullPropertyPath(SingleValueNode node) { string path = null; SingleValueNode parent = null; switch (node.Kind) { case QueryNodeKind.SingleComplexNode: var complexNode = (SingleComplexNode)node; path = complexNode.Property.Name; parent = complexNode.Source; break; case QueryNodeKind.SingleValuePropertyAccess: var propertyNode = ((SingleValuePropertyAccessNode)node); path = propertyNode.Property.Name; parent = propertyNode.Source; break; case QueryNodeKind.SingleNavigationNode: var navNode = ((SingleNavigationNode)node); path = navNode.NavigationProperty.Name; parent = navNode.Source; break; } if (parent != null) { var parentPath = GetFullPropertyPath(parent); if (parentPath != null) { path = parentPath + "\\" + path; } } return(path); }
/// <summary> /// The recursive method that validate most of the query node type is of SingleValueNode type. /// </summary> /// <param name="node"></param> /// <param name="settings"></param> private void ValidateSingleValueNode(SingleValueNode node, ODataValidationSettings settings) { switch (node.Kind) { case QueryNodeKind.BinaryOperator: ValidateBinaryOperatorNode(node as BinaryOperatorNode, settings); break; case QueryNodeKind.Constant: ValidateConstantNode(node as ConstantNode, settings); break; case QueryNodeKind.Convert: ValidateConvertNode(node as ConvertNode, settings); break; case QueryNodeKind.EntityRangeVariableReference: ValidateRangeVariable((node as EntityRangeVariableReferenceNode).RangeVariable, settings); break; case QueryNodeKind.NonentityRangeVariableReference: ValidateRangeVariable((node as NonentityRangeVariableReferenceNode).RangeVariable, settings); break; case QueryNodeKind.SingleValuePropertyAccess: ValidateSingleValuePropertyAccessNode(node as SingleValuePropertyAccessNode, settings); break; case QueryNodeKind.UnaryOperator: ValidateUnaryOperatorNode(node as UnaryOperatorNode, settings); break; case QueryNodeKind.SingleValueFunctionCall: ValidateSingleValueFunctionCallNode(node as SingleValueFunctionCallNode, settings); break; case QueryNodeKind.SingleNavigationNode: SingleNavigationNode navigationNode = node as SingleNavigationNode; ValidateNavigationPropertyNode(navigationNode.Source, navigationNode.NavigationProperty, settings); break; case QueryNodeKind.Any: ValidateAnyNode(node as AnyNode, settings); break; case QueryNodeKind.All: ValidateAllNode(node as AllNode, settings); break; default: throw new ODataException(Error.Format(SRResources.QueryNodeBindingNotSupported, node.Kind, typeof(FilterQueryValidator).Name)); } }
/// <summary> /// The recursive method that validate most of the query node type is of SingleValueNode type. /// </summary> /// <param name="node"></param> /// <param name="settings"></param> private void ValidateSingleValueNode(SingleValueNode node, ODataValidationSettings settings) { switch (node.Kind) { case QueryNodeKind.BinaryOperator: ValidateBinaryOperatorNode(node as BinaryOperatorNode, settings); break; case QueryNodeKind.Constant: ValidateConstantNode(node as ConstantNode, settings); break; case QueryNodeKind.Convert: ValidateConvertNode(node as ConvertNode, settings); break; case QueryNodeKind.EntityRangeVariableReference: ValidateRangeVariable((node as EntityRangeVariableReferenceNode).RangeVariable, settings); break; case QueryNodeKind.NonentityRangeVariableReference: ValidateRangeVariable((node as NonentityRangeVariableReferenceNode).RangeVariable, settings); break; case QueryNodeKind.SingleValuePropertyAccess: ValidateSingleValuePropertyAccessNode(node as SingleValuePropertyAccessNode, settings); break; case QueryNodeKind.UnaryOperator: ValidateUnaryOperatorNode(node as UnaryOperatorNode, settings); break; case QueryNodeKind.SingleValueFunctionCall: ValidateSingleValueFunctionCallNode(node as SingleValueFunctionCallNode, settings); break; case QueryNodeKind.SingleNavigationNode: SingleNavigationNode navigationNode = node as SingleNavigationNode; ValidateNavigationPropertyNode(navigationNode.Source, navigationNode.NavigationProperty, settings); break; case QueryNodeKind.SingleEntityCast: ValidateSingleEntityCastNode(node as SingleEntityCastNode, settings); break; case QueryNodeKind.Any: ValidateAnyNode(node as AnyNode, settings); break; case QueryNodeKind.All: ValidateAllNode(node as AllNode, settings); break; } }
private static bool IsSubstringOfFunctionCall(SingleValueNode expression) { // If necessary, unwrap SingleValueFunctionCall from ConvertNode if (expression.Kind == QueryNodeKind.Convert) { expression = ((ConvertNode)expression).Source; } if (expression.Kind == QueryNodeKind.SingleValueFunctionCall) { var functionCallExpression = (SingleValueFunctionCallNode)expression; return string.Equals(functionCallExpression.Name, "substringof", StringComparison.OrdinalIgnoreCase); } return false; }
/// <summary> /// Initialises a new instance of the <see cref="BinaryOperatorNode"/> class. /// </summary> /// <param name="left">The left query node.</param> /// <param name="operatorKind">Kind of the operator.</param> /// <param name="right">The right query node.</param> public BinaryOperatorNode(SingleValueNode left, BinaryOperatorKind operatorKind, SingleValueNode right) { this.Left = left; this.OperatorKind = operatorKind; this.Right = right; }
/// <summary> /// The recursive method that validate most of the query node type is of SingleValueNode type. /// </summary> /// <param name="node"></param> /// <param name="settings"></param> private void ValidateSingleValueNode(SingleValueNode node, ODataValidationSettings settings) { switch (node.Kind) { case QueryNodeKind.BinaryOperator: ValidateBinaryOperatorNode(node as BinaryOperatorNode, settings); break; case QueryNodeKind.Constant: ValidateConstantNode(node as ConstantNode, settings); break; case QueryNodeKind.Convert: ValidateConvertNode(node as ConvertNode, settings); break; case QueryNodeKind.EntityRangeVariableReference: ValidateRangeVariable((node as EntityRangeVariableReferenceNode).RangeVariable, settings); break; case QueryNodeKind.NonentityRangeVariableReference: ValidateRangeVariable((node as NonentityRangeVariableReferenceNode).RangeVariable, settings); break; case QueryNodeKind.SingleValuePropertyAccess: ValidateSingleValuePropertyAccessNode(node as SingleValuePropertyAccessNode, settings); break; case QueryNodeKind.UnaryOperator: ValidateUnaryOperatorNode(node as UnaryOperatorNode, settings); break; case QueryNodeKind.SingleValueFunctionCall: ValidateSingleValueFunctionCallNode(node as SingleValueFunctionCallNode, settings); break; case QueryNodeKind.SingleNavigationNode: SingleNavigationNode navigationNode = node as SingleNavigationNode; ValidateNavigationPropertyNode(navigationNode.Source, navigationNode.NavigationProperty, settings); break; case QueryNodeKind.SingleEntityCast: ValidateSingleEntityCastNode(node as SingleEntityCastNode, settings); break; case QueryNodeKind.Any: ValidateAnyNode(node as AnyNode, settings); break; case QueryNodeKind.All: ValidateAllNode(node as AllNode, settings); break; case QueryNodeKind.NamedFunctionParameter: case QueryNodeKind.SingleValueOpenPropertyAccess: // Unused or have unknown uses. case QueryNodeKind.SingleEntityFunctionCall: // Used for some 'cast' calls but not supported here or in FilterBinder. default: throw Error.NotSupported(SRResources.QueryNodeValidationNotSupported, node.Kind, typeof(FilterQueryValidator).Name); } }
/// <summary> /// Creates a <see cref="SearchClause"/>. /// </summary> /// <param name="expression">The filter expression - this should evaluate to a single boolean value. Cannot be null.</param> /// <exception cref="System.ArgumentNullException">Throws if the input expression or rangeVariable is null.</exception> public SearchClause(SingleValueNode expression) { ExceptionUtils.CheckArgumentNotNull(expression, "expression"); this.expression = expression; }
/// <summary> /// Initialises a new instance of the <see cref="UnaryOperatorNode"/> class. /// </summary> /// <param name="operand">The operand of the unary operator.</param> /// <param name="operatorKind">Kind of the operator.</param> public UnaryOperatorNode(SingleValueNode operand, UnaryOperatorKind operatorKind) { this.Operand = operand; this.OperatorKind = operatorKind; }
private string BindNavigationPropertyNode(SingleValueNode singleValueNode, IEdmNavigationProperty edmNavigationProperty) { return Bind(singleValueNode) + "." + edmNavigationProperty.Name; }