public void RightShouldBeSetCorrectly() { ConstantNode left = new ConstantNode(1); ConstantNode right = new ConstantNode(2); BinaryOperatorNode operatorNode = new BinaryOperatorNode(BinaryOperatorKind.Add, left, right); operatorNode.Right.Should().Be(right); }
public void KindIsBinaryOperatorNode() { ConstantNode left = new ConstantNode(1); ConstantNode right = new ConstantNode(2); BinaryOperatorNode operatorNode = new BinaryOperatorNode(BinaryOperatorKind.Add, left, right); operatorNode.InternalKind.Should().Be(InternalQueryNodeKind.BinaryOperator); }
public void ToODataString_EscapesThe_Uri() { //updatedat gt datetimeoffset'2014-04-04T07:00:00.0000000+00:00' var datetime1 = new ConstantNode(new DateTimeOffset(2014, 4, 4, 7, 0, 0, TimeSpan.FromHours(0))); var updatedAt = new MemberAccessNode(null, "updatedat"); var gt1 = new BinaryOperatorNode(BinaryOperatorKind.GreaterThan, updatedAt, datetime1); // updatedat gt datetime'2014-04-04T07:0:0.000Z' var datetime2 = new ConstantNode(new DateTime(2014, 4, 4, 7, 0, 0, DateTimeKind.Utc)); var someDate = new MemberAccessNode(null, "someDate"); var gt2 = new BinaryOperatorNode(BinaryOperatorKind.GreaterThan, someDate, datetime2); // startswith(text,'this&''%%=,?#') var text = new MemberAccessNode(null, "text"); var value = new ConstantNode("this&'%%=,?#"); var startswith = new FunctionCallNode("startswith", new QueryNode[] { text, value }); //updatedat gt datetimeoffset'2014-04-04T07:00:00.0000000+00:00' and startswith(text,'this&''%%=,?#') var and2 = new BinaryOperatorNode(BinaryOperatorKind.And, gt2, startswith); var and1 = new BinaryOperatorNode(BinaryOperatorKind.And, gt1, and2); var desc = new MobileServiceTableQueryDescription("someTable") { Filter = and1 }; Assert.AreEqual(desc.ToODataString(), EscapedODataString); }
public void TypeReferenceIsSetCorrectlyFromOperands() { ConstantNode left = new ConstantNode(1); ConstantNode right = new ConstantNode(2); BinaryOperatorNode operatorNode = new BinaryOperatorNode(BinaryOperatorKind.Add, left, right); operatorNode.TypeReference.FullName().Should().Be("Edm.Int32"); }
public void FilterOptionSetCorrectly() { BinaryOperatorNode filterExpression = new BinaryOperatorNode(BinaryOperatorKind.Equal, new ConstantNode(1), new ConstantNode(1)); FilterClause filterClause = new FilterClause(filterExpression, new EntityRangeVariable(ExpressionConstants.It, HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet())); ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), HardCodedTestModel.GetPeopleSet(), null, filterClause, null, null, null, null, null, null); expansion.FilterOption.Expression.ShouldBeBinaryOperatorNode(BinaryOperatorKind.Equal); expansion.FilterOption.Expression.As<BinaryOperatorNode>().Left.ShouldBeConstantQueryNode(1); expansion.FilterOption.Expression.As<BinaryOperatorNode>().Right.ShouldBeConstantQueryNode(1); }
private QueryNode ParseLogicalOr() { QueryNode left = this.ParseLogicalAnd(); while (this.lexer.Token.Kind == QueryTokenKind.Or) { this.lexer.NextToken(); QueryNode right = this.ParseLogicalAnd(); left = new BinaryOperatorNode(BinaryOperatorKind.Or, left, right); } return left; }
//$filter=EnterpriseName%20eq%20%27DIEGO_520%27 public BinaryOperatorResolver(BinaryOperatorNode binaryOperator) { if (binaryOperator != null) { var property = binaryOperator.Left as SingleValuePropertyAccessNode ?? binaryOperator.Right as SingleValuePropertyAccessNode; var constant = binaryOperator.Left as ConstantNode ?? binaryOperator.Right as ConstantNode; if (property != null && property.Property != null && constant != null && constant.Value != null) { Property = property.Property.Name; Operator = binaryOperator.OperatorKind; Value = constant.LiteralText; } } }
public BinaryExpressionNode(ExpressionNode left, ExpressionNode right, BinaryOperatorNode operatorNode) { if (left == null) ThrowHelper.ThrowArgumentNullException(() => left); if (right == null) ThrowHelper.ThrowArgumentNullException(() => right); if (operatorNode == null) ThrowHelper.ThrowArgumentNullException(() => operatorNode); Left = left; Right = right; Operator = operatorNode; AddChildren(Left, Right, Operator); }
private BinaryOperatorNode Process(BinaryOperatorNode node) { Process(node.Left); Process(node.Right); return(node); }
private QueryNode ParseAdditive() { QueryNode left = this.ParseMultiplicative(); while (this.lexer.Token.Kind == QueryTokenKind.Add || this.lexer.Token.Kind == QueryTokenKind.Sub) { QueryTokenKind opKind = this.lexer.Token.Kind; this.lexer.NextToken(); QueryNode right = this.ParseMultiplicative(); switch (opKind) { case QueryTokenKind.Add: left = new BinaryOperatorNode(BinaryOperatorKind.And, left, right); break; case QueryTokenKind.Sub: left = new BinaryOperatorNode(BinaryOperatorKind.Subtract, left, right); break; } } return left; }
private static AllowedLogicalOperators ToLogicalOperator(BinaryOperatorNode binaryNode) { AllowedLogicalOperators result = AllowedLogicalOperators.None; switch (binaryNode.OperatorKind) { case BinaryOperatorKind.Equal: result = AllowedLogicalOperators.Equal; break; case BinaryOperatorKind.NotEqual: result = AllowedLogicalOperators.NotEqual; break; case BinaryOperatorKind.And: result = AllowedLogicalOperators.And; break; case BinaryOperatorKind.GreaterThan: result = AllowedLogicalOperators.GreaterThan; break; case BinaryOperatorKind.GreaterThanOrEqual: result = AllowedLogicalOperators.GreaterThanOrEqual; break; case BinaryOperatorKind.LessThan: result = AllowedLogicalOperators.LessThan; break; case BinaryOperatorKind.LessThanOrEqual: result = AllowedLogicalOperators.LessThanOrEqual; break; case BinaryOperatorKind.Or: result = AllowedLogicalOperators.Or; break; default: // should never be here Contract.Assert(false, "ToLogicalOperator should never be here."); break; } return result; }
public override FilterNode <ClrValue> Visit(BinaryOperatorNode nodeIn) { if (nodeIn.OperatorKind == BinaryOperatorKind.And) { return(ClrFilter.And(nodeIn.Left.Accept(this), nodeIn.Right.Accept(this))); } if (nodeIn.OperatorKind == BinaryOperatorKind.Or) { return(ClrFilter.Or(nodeIn.Left.Accept(this), nodeIn.Right.Accept(this))); } if (nodeIn.Left is SingleValueFunctionCallNode functionNode) { if (string.Equals(functionNode.Name, "geo.distance", StringComparison.OrdinalIgnoreCase) && nodeIn.OperatorKind == BinaryOperatorKind.LessThan) { var valueDistance = (double)ConstantWithTypeVisitor.Visit(nodeIn.Right).Value !; if (functionNode.Parameters.ElementAt(1) is not ConstantNode constantNode) { throw new NotSupportedException(); } if (constantNode.Value is not GeographyPoint geographyPoint) { throw new NotSupportedException(); } var property = PropertyPathVisitor.Visit(functionNode.Parameters.ElementAt(0)); return(ClrFilter.Lt(property, new FilterSphere(geographyPoint.Longitude, geographyPoint.Latitude, valueDistance))); } else { var regexFilter = Visit(functionNode); var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); if (value.ValueType == ClrValueType.Boolean && value.Value is bool booleanRight) { if ((nodeIn.OperatorKind == BinaryOperatorKind.Equal && !booleanRight) || (nodeIn.OperatorKind == BinaryOperatorKind.NotEqual && booleanRight)) { regexFilter = ClrFilter.Not(regexFilter); } return(regexFilter); } } } else { if (nodeIn.OperatorKind == BinaryOperatorKind.NotEqual) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Ne(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.Equal) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Eq(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.LessThan) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Lt(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.LessThanOrEqual) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Le(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThan) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Gt(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThanOrEqual) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Ge(PropertyPathVisitor.Visit(nodeIn.Left), value)); } } throw new NotSupportedException(); }
/// <summary> /// Compares binary operator query nodes. /// </summary> /// <param name="left">Left side of comparison</param> /// <param name="right">Right side of comparison</param> /// <returns>True if equal, otherwise false</returns> private bool Compare(BinaryOperatorNode left, BinaryOperatorNode right) { if (left.OperatorKind != right.OperatorKind) return false; if (left.TypeReference != right.TypeReference) return false; if (!this.Compare(left.Left, right.Left)) return false; return this.Compare(left.Right, right.Right); }
private static void BuildNavigationWithAny() { // Request URI var requestUri = new Uri("Students?$filter=StudentId gt 100", UriKind.Relative); var requestODataUri = new ODataUriParser(SchoolModel.Model, requestUri).ParseUri(); var requestFilterExpression = requestODataUri.Filter.Expression; // URI that contains additional condition var conditionUri = new Uri("Students?$filter=Courses/any(c:c/Teacher/Education/Degrees/any(d:d/Category eq 'English Literature'))", UriKind.Relative); var conditionODataUri = new ODataUriParser(SchoolModel.Model, conditionUri).ParseUri(); var conditionExpression = conditionODataUri.Filter.Expression; // New $filter expression var newFilterExpression = new BinaryOperatorNode(BinaryOperatorKind.And, requestFilterExpression, conditionExpression); requestODataUri.Filter = new FilterClause(newFilterExpression, requestODataUri.Filter.RangeVariable); var builder = new ODataUriBuilder(ODataUrlConventions.Default, requestODataUri); Console.WriteLine(builder.BuildUri()); // http://host/Students?$filter=StudentId%20gt%20100%20and%20Courses%2Fany%28c%3Ac%2FTeacher%2FEducation%2FDegrees%2Fany%28d%3Ad%2FCategory%20eq%20%27English%20Literature%27%29%29 // http://host/Students?$filter=StudentId gt 100 and Courses/any(c:c/Teacher/Education/Degrees/any(d:d/Category eq 'English Literature')) }
public override Expression Visit(BinaryOperatorNode nodeIn) { Expression left = TranslateNode(nodeIn.Left); Expression right = TranslateNode(nodeIn.Right); if (left.Type != right.Type) { Type leftType = left.Type; Type rightType = right.Type; if (OeExpressionHelper.IsNullable(left) && !OeExpressionHelper.IsNull(left)) { if (OeExpressionHelper.IsNull(right)) { ConstantExpression newConstant = Expression.Constant(null, leftType); ReplaceConstant((ConstantExpression)right, newConstant); right = newConstant; } else { leftType = Nullable.GetUnderlyingType(left.Type); } } else if (OeExpressionHelper.IsNullable(right) && !OeExpressionHelper.IsNull(right)) { if (OeExpressionHelper.IsNull(left)) { ConstantExpression newConstant = Expression.Constant(null, rightType); ReplaceConstant((ConstantExpression)left, newConstant); left = newConstant; } else { rightType = Nullable.GetUnderlyingType(right.Type); } } if (right.Type != left.Type) { if (left is ConstantExpression) { ConstantExpression oldConstant = left as ConstantExpression; ConstantExpression newConstant = OeExpressionHelper.ConstantChangeType(oldConstant, rightType); if (oldConstant != newConstant) { ReplaceConstant(oldConstant, newConstant); } left = Expression.Convert(newConstant, right.Type); } else if (right is ConstantExpression) { ConstantExpression oldConstant = right as ConstantExpression; ConstantExpression newConstant = OeExpressionHelper.ConstantChangeType(oldConstant, leftType); if (oldConstant != newConstant) { ReplaceConstant(oldConstant, newConstant); } right = Expression.Convert(newConstant, left.Type); } else { Type precedenceType = OeExpressionHelper.GetTypeConversion(left.Type, right.Type); if (left.Type != precedenceType) { left = Expression.Convert(left, precedenceType); } if (right.Type != precedenceType) { right = Expression.Convert(right, precedenceType); } } } } ExpressionType binaryType = OeExpressionHelper.ToExpressionType(nodeIn.OperatorKind); if (left.Type == typeof(String) && !(binaryType == ExpressionType.Equal || binaryType == ExpressionType.NotEqual)) { Func <String, String, int> compareToFunc = String.Compare; MethodCallExpression compareToCall = Expression.Call(null, compareToFunc.GetMethodInfo(), left, right); return(Expression.MakeBinary(binaryType, compareToCall, OeConstantToVariableVisitor.ZeroStringCompareConstantExpression)); } return(Expression.MakeBinary(binaryType, left, right)); }
/// <summary> /// Binds the specified <see cref="BinaryOperatorNode"/>. /// </summary> /// <param name="binaryOperatorNode">The <see cref="BinaryOperatorNode"/> to bind.</param> protected abstract void Bind(BinaryOperatorNode binaryOperatorNode);
private double Evaluate(BaseNode node) { double result = 0; if (node == null) { return(0); } // as a constant node ConstantNumbericalNode constantNode = node as ConstantNumbericalNode; if (constantNode != null) { result = constantNode.Value; return(result); } // as a variable VariableNode variableNode = node as VariableNode; if (variableNode != null) { // if the variable node name is in the dictionary if (this.keyValuePairs.ContainsKey(variableNode.Name)) { result = this.keyValuePairs[variableNode.Name]; return(result); } // otherwise return 0 return(0); } // an operator node BinaryOperatorNode operatorNode = node as BinaryOperatorNode; if (operatorNode != null) { // choose operator switch (operatorNode.BinaryOperator) { case '+': result = this.Evaluate(operatorNode.Left) + this.Evaluate(operatorNode.Right); break; case '-': result = this.Evaluate(operatorNode.Left) - this.Evaluate(operatorNode.Right); break; case '*': result = this.Evaluate(operatorNode.Left) * this.Evaluate(operatorNode.Right); break; case '/': result = this.Evaluate(operatorNode.Left) / this.Evaluate(operatorNode.Right); break; } return(result); } return(0); }
public void Visit(BinaryOperatorNode op) { throw new NotSupportedException(); }
public override FilterNode <ClrValue> Visit(BinaryOperatorNode nodeIn) { if (nodeIn.OperatorKind == BinaryOperatorKind.And) { return(ClrFilter.And(nodeIn.Left.Accept(this), nodeIn.Right.Accept(this))); } if (nodeIn.OperatorKind == BinaryOperatorKind.Or) { return(ClrFilter.Or(nodeIn.Left.Accept(this), nodeIn.Right.Accept(this))); } if (nodeIn.Left is SingleValueFunctionCallNode functionNode) { var regexFilter = Visit(functionNode); var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); if (value.ValueType == ClrValueType.Boolean && value.Value is bool booleanRight) { if ((nodeIn.OperatorKind == BinaryOperatorKind.Equal && !booleanRight) || (nodeIn.OperatorKind == BinaryOperatorKind.NotEqual && booleanRight)) { regexFilter = ClrFilter.Not(regexFilter); } return(regexFilter); } } else { if (nodeIn.OperatorKind == BinaryOperatorKind.NotEqual) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Ne(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.Equal) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Eq(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.LessThan) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Lt(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.LessThanOrEqual) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Le(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThan) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Gt(PropertyPathVisitor.Visit(nodeIn.Left), value)); } if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThanOrEqual) { var value = ConstantWithTypeVisitor.Visit(nodeIn.Right); return(ClrFilter.Ge(PropertyPathVisitor.Visit(nodeIn.Left), value)); } } throw new NotSupportedException(); }
/// <summary> /// Writes binary operator node to string /// </summary> /// <param name="node">Node to write to string</param> /// <returns>String representation of node.</returns> private static string ToString(BinaryOperatorNode node) { if (node != null) { return tabHelper.Indent(() => ToString(node.Left)) + tabHelper.Prefix + node.OperatorKind + tabHelper.Indent(() => (ToString(node.Right))); } return String.Empty; }
public override Expression Visit(BinaryOperatorNode nodeIn) { Expression left = TranslateNode(nodeIn.Left); Expression right = TranslateNode(nodeIn.Right); if (left.Type != right.Type) { Type leftType = left.Type; Type rightType = right.Type; Type?leftUnderlyingType = Nullable.GetUnderlyingType(left.Type); if (leftUnderlyingType != null && !OeExpressionHelper.IsNull(left)) { if (OeExpressionHelper.IsNull(right)) { right = OeConstantToVariableVisitor.NullConstantExpression; } else { leftType = leftUnderlyingType; } } else { Type?rightUnderlyingType = Nullable.GetUnderlyingType(right.Type); if (rightUnderlyingType != null && !OeExpressionHelper.IsNull(right)) { if (OeExpressionHelper.IsNull(left)) { left = OeConstantToVariableVisitor.NullConstantExpression; } else { rightType = rightUnderlyingType; } } } if (right.Type != left.Type) { if (left is ConstantExpression leftOldConstant) { ConstantExpression newConstant = OeExpressionHelper.ConstantChangeType(leftOldConstant, rightType); if (leftOldConstant != newConstant) { ReplaceConstant(leftOldConstant, newConstant); } if (newConstant.Value != null) { left = Expression.Convert(newConstant, right.Type); } } else if (right is ConstantExpression rightOldConstant) { ConstantExpression newConstant = OeExpressionHelper.ConstantChangeType(rightOldConstant, leftType); if (rightOldConstant != newConstant) { ReplaceConstant(rightOldConstant, newConstant); } if (newConstant.Value != null) { right = Expression.Convert(newConstant, left.Type); } } else { Type precedenceType = OeExpressionHelper.GetTypeConversion(left.Type, right.Type); if (left.Type != precedenceType) { left = Expression.Convert(left, precedenceType); } if (right.Type != precedenceType) { right = Expression.Convert(right, precedenceType); } } } } ExpressionType binaryType = OeExpressionHelper.ToExpressionType(nodeIn.OperatorKind); if (!(binaryType == ExpressionType.Equal || binaryType == ExpressionType.NotEqual)) { if (left.Type == typeof(String)) { Func <String, String, int> compareToFunc = String.Compare; MethodCallExpression compareToCall = Expression.Call(null, compareToFunc.GetMethodInfo(), left, right); return(Expression.MakeBinary(binaryType, compareToCall, OeConstantToVariableVisitor.ZeroStringCompareConstantExpression)); } Type?underlyingType; if (left.Type.IsEnum) { Type enumUnderlyingType = Enum.GetUnderlyingType(left.Type); left = ConvertEnumExpression(left, enumUnderlyingType); right = ConvertEnumExpression(right, enumUnderlyingType); } else if ((underlyingType = Nullable.GetUnderlyingType(left.Type)) != null && underlyingType.IsEnum) { Type enumUnderlyingType = Enum.GetUnderlyingType(underlyingType); Type nullableUnderlyingType = typeof(Nullable <>).MakeGenericType(enumUnderlyingType); left = ConvertEnumExpression(left, nullableUnderlyingType); right = ConvertEnumExpression(right, nullableUnderlyingType); } } return(Expression.MakeBinary(binaryType, left, right));
private string BindBinaryOperatorNode(BinaryOperatorNode binaryOperatorNode) { var left = Bind(binaryOperatorNode.Left); var right = Bind(binaryOperatorNode.Right); return "(" + left + " " + ToString(binaryOperatorNode.OperatorKind) + " " + right + ")"; }
private void UpdateDeltaToken() { this.deltaToken = this.maxUpdatedAt; if (this.ordered) { this.Query.Ordering.Clear(); this.Query.Ordering.Add(orderByUpdatedAtNode); } // .NET runtime system properties are of datetimeoffset type so we'll use the datetimeoffset odata token QueryNode tokenNode = new ConstantNode(deltaToken); QueryNode greaterThanDeltaNode = new BinaryOperatorNode(BinaryOperatorKind.GreaterThanOrEqual, updatedAtNode, tokenNode); if (this.originalFilter == null) { this.Query.Filter = greaterThanDeltaNode; } else { var originalFilterAndGreaterThanDeltaNode = new BinaryOperatorNode(BinaryOperatorKind.And, this.originalFilter, greaterThanDeltaNode); this.Query.Filter = originalFilterAndGreaterThanDeltaNode; } }
public virtual BinaryOperatorNode Visit(BinaryOperatorNode bin) { return(bin); }
/// <summary> /// override this method to restrict the binary operators inside the filter query. That includes all the logical operators except 'not' and all math operators. /// </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="binaryOperatorNode"></param> /// <param name="settings"></param> public virtual void ValidateBinaryOperatorNode(BinaryOperatorNode binaryOperatorNode, ODataValidationSettings settings) { if (binaryOperatorNode == null) { throw Error.ArgumentNull("binaryOperatorNode"); } if (settings == null) { throw Error.ArgumentNull("settings"); } // base case goes switch (binaryOperatorNode.OperatorKind) { case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.And: case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.LessThanOrEqual: case BinaryOperatorKind.Or: // binary logical operators ValidateLogicalOperator(binaryOperatorNode, settings); break; default: // math operators ValidateArithmeticOperator(binaryOperatorNode, settings); break; } }
public override void Init(AstContext context, ParseTreeNode parseNode) { Left = parseNode.ChildNodes[0].AstNode as Node; BinaryOperator = (parseNode.ChildNodes[1].AstNode as BinaryOperatorNode); Right = parseNode.ChildNodes[2].AstNode as Node; }
private string ResolveLamdaNode(LambdaNode node) { BinaryOperatorNode expression = node.Body as BinaryOperatorNode; string alias = ""; string propertyName = ""; string parentPropertyName = ""; string rootPropertyName = ""; //Property at root if (expression.Left is NonentityRangeVariableReferenceNode) { var leftNode = expression.Left as NonentityRangeVariableReferenceNode; alias = leftNode.Name; if (node.Source is CollectionPropertyAccessNode) { propertyName = (node.Source as CollectionPropertyAccessNode).Property.Name; } } else if (expression.Left is SingleValuePropertyAccessNode) { var leftNode = expression.Left as SingleValuePropertyAccessNode; if (leftNode.Source is NonentityRangeVariableReferenceNode) { alias = (leftNode.Source as NonentityRangeVariableReferenceNode).Name; } else if (leftNode.Source is EntityRangeVariableReferenceNode) { alias = (leftNode.Source as EntityRangeVariableReferenceNode).Name; } propertyName = leftNode.Property.Name; if (node.Source is CollectionPropertyAccessNode) { parentPropertyName = (node.Source as CollectionPropertyAccessNode).Property.Name; var sourceNode = node.Source as CollectionPropertyAccessNode; if (sourceNode.Source is SingleValuePropertyAccessNode) { var rootNode = sourceNode.Source as SingleValuePropertyAccessNode; rootPropertyName = rootNode.Property.Name; } } else if (node.Source is CollectionNavigationNode) { var sourceNode = node.Source as CollectionNavigationNode; parentPropertyName = sourceNode.NavigationProperty.Name; if (sourceNode.Source is SingleNavigationNode) { var rootNode = sourceNode.Source as SingleNavigationNode; rootPropertyName = rootNode.NavigationProperty.Name; } } } var rightExpression = (expression.Right as ConstantNode).LiteralText; var mappedPropertyName = _fieldMapper.Map(propertyName, parentPropertyName, rootPropertyName); var lamdaProperty = node.Kind == QueryNodeKind.Any ? "any" : "all"; var expressionFormat = $"{mappedPropertyName}/{lamdaProperty}({alias}: {alias} eq {rightExpression})"; return(expressionFormat); }
public override void ValidateBinaryOperatorNode(BinaryOperatorNode binaryOperatorNode, ODataValidationSettings settings) { IncrementCount("ValidateBinaryOperatorQueryNode"); base.ValidateBinaryOperatorNode(binaryOperatorNode, settings); }
/// <summary> /// Visit a <see cref="BinaryOperatorNode"/> /// </summary> public abstract T Visit(BinaryOperatorNode node);
private string BindBinaryOperatorNode(BinaryOperatorNode binaryOperatorNode) { var left = Bind(binaryOperatorNode.Left); var right = Bind(binaryOperatorNode.Right); if (binaryOperatorNode.OperatorKind == BinaryOperatorKind.Equal && right == "null") return "(" + left + " is null)"; if (binaryOperatorNode.OperatorKind == BinaryOperatorKind.NotEqual && right == "null") return "(" + left + " is not null)"; return "(" + left + " " + ToString(binaryOperatorNode.OperatorKind) + " " + right + ")"; }
private static void BuildFilterWithNestedAny() { var personTypeRef = new EdmEntityTypeReference(TripPinModel.Person, false); var tripTypeRef = new EdmEntityTypeReference(TripPinModel.Trip, false); var friendsProp = (IEdmNavigationProperty)TripPinModel.Person.FindProperty("Friends"); var tripsProp = (IEdmNavigationProperty)TripPinModel.Person.FindProperty("Trips"); var budgetProp = TripPinModel.Trip.FindProperty("Budget"); var topIt = new EntityRangeVariable("$it", personTypeRef, TripPinModel.PeopleSet); var topItRef = new EntityRangeVariableReferenceNode("$it", topIt); var friendsNavNode0 = new CollectionNavigationNode(friendsProp, topItRef); var e0 = new EntityRangeVariable("e0", personTypeRef, friendsNavNode0); var e0Ref = new EntityRangeVariableReferenceNode("e0", e0); var friendsNavNode1 = new CollectionNavigationNode(friendsProp, e0Ref); var e1 = new EntityRangeVariable("e1", personTypeRef, friendsNavNode1); var e1Ref = new EntityRangeVariableReferenceNode("e1", e1); var tripNavNode = new CollectionNavigationNode(tripsProp, e1Ref); var e2 = new EntityRangeVariable("e2", tripTypeRef, friendsNavNode1); var e2Ref = new EntityRangeVariableReferenceNode("e2", e2); var bugetNode = new SingleValuePropertyAccessNode(e2Ref, budgetProp); var gt = new BinaryOperatorNode( BinaryOperatorKind.GreaterThan, bugetNode, new ConstantNode(1200, "1200")); var any2 = new AnyNode(new Collection<RangeVariable> { e2 }, e2) { Body = gt, Source = tripNavNode }; var any1 = new AnyNode(new Collection<RangeVariable> { e1 }, e1) { Body = any2, Source = friendsNavNode1 }; var any0 = new AnyNode(new Collection<RangeVariable> { e0 }, e0) { Body = any1, Source = friendsNavNode0 }; var odataUri = new ODataUri { Path = new ODataPath(new EntitySetSegment(TripPinModel.PeopleSet)), ServiceRoot = TripPinRoot, Filter = new FilterClause(any0, topIt) }; var builder = new ODataUriBuilder(ODataUrlConventions.Default, odataUri); Console.WriteLine(builder.BuildUri()); // http://services.odata.org/V4/TripPinService/People?$filter=Friends%2Fany(e0:e0%2FFriends%2Fany(e1:e1%2FTrips%2Fany(e2:e2%2FBudget gt 1200))) }
public override void ValidateLogicalOperator(BinaryOperatorNode binaryNode, ODataValidationSettings settings) { IncrementCount("ValidateLogicalOperator"); base.ValidateLogicalOperator(binaryNode, settings); }
public static IEnumerable<FilterTestCase> UnaryOperatorTestCases() { // Single unary operator UnaryOperatorNode left = new UnaryOperatorNode(UnaryOperatorKind.Negate, new ConstantNode(1)); yield return new FilterTestCase() { Filter = UnaryOperatorKind.Negate.ToOperatorName() + "(1) le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, left, new ConstantNode(5)) }; yield return new FilterTestCase() { Filter = UnaryOperatorKind.Not.ToOperatorName() + " true", ExpectedFilterCondition = new UnaryOperatorNode(UnaryOperatorKind.Not, new ConstantNode(true)) }; // Two unary operators UnaryOperatorNode inner = new UnaryOperatorNode(UnaryOperatorKind.Negate, new ConstantNode(1)); UnaryOperatorNode outer = new UnaryOperatorNode(UnaryOperatorKind.Negate, inner); yield return new FilterTestCase() { Filter = UnaryOperatorKind.Negate.ToOperatorName() + "(" + UnaryOperatorKind.Negate.ToOperatorName() + "(1)) le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, outer, new ConstantNode(5)) }; UnaryOperatorNode inner2 = new UnaryOperatorNode(UnaryOperatorKind.Not, new ConstantNode(true)); yield return new FilterTestCase() { Filter = UnaryOperatorKind.Not.ToOperatorName() + " " + UnaryOperatorKind.Not.ToOperatorName() + " true", ExpectedFilterCondition = new UnaryOperatorNode(UnaryOperatorKind.Not, inner2) }; // Unary and binary operator. UnaryOperatorNode inner3 = new UnaryOperatorNode(UnaryOperatorKind.Not, new ConstantNode(true)); yield return new FilterTestCase() { Filter = UnaryOperatorKind.Not.ToOperatorName() + " true " + BinaryOperatorKind.Equal.ToOperatorName() + " false", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.Equal, inner3, new ConstantNode(false)) }; // With parenthesis BinaryOperatorNode innerBinary = new BinaryOperatorNode(BinaryOperatorKind.Add, new ConstantNode(2), new ConstantNode(3)); UnaryOperatorNode outer2 = new UnaryOperatorNode(UnaryOperatorKind.Negate, innerBinary); yield return new FilterTestCase() { Filter = UnaryOperatorKind.Negate.ToOperatorName() + " (2 " + BinaryOperatorKind.Add.ToOperatorName() + " 3) le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, outer2, new ConstantNode(5)) }; BinaryOperatorNode innerBinary2 = new BinaryOperatorNode(BinaryOperatorKind.Equal, new ConstantNode(true), new ConstantNode(false)); yield return new FilterTestCase() { Filter = UnaryOperatorKind.Not.ToOperatorName() + " (true " + BinaryOperatorKind.Equal.ToOperatorName() + " false)", ExpectedFilterCondition = new UnaryOperatorNode(UnaryOperatorKind.Not, innerBinary2) }; }
/// <summary> /// Override this method for the Arithmetic operators, including add, sub, mul, div, mod. /// </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="binaryNode"></param> /// <param name="settings"></param> public virtual void ValidateArithmeticOperator(BinaryOperatorNode binaryNode, ODataValidationSettings settings) { if (binaryNode == null) { throw Error.ArgumentNull("binaryNode"); } if (settings == null) { throw Error.ArgumentNull("settings"); } AllowedArithmeticOperators arithmeticOperator = ToArithmeticOperator(binaryNode); if ((settings.AllowedArithmeticOperators & arithmeticOperator) != arithmeticOperator) { // this means the given logical operator is not allowed throw new ODataException(Error.Format(SRResources.NotAllowedArithmeticOperator, arithmeticOperator, "AllowedArithmeticOperators")); } // recursion case goes here ValidateQueryNode(binaryNode.Left, settings); ValidateQueryNode(binaryNode.Right, settings); }
static IEnumerable<FilterTestCase> BinaryOperatorTestCases() { #region Single operator foreach (var operatorKind in QueryTestUtils.BinaryOperatorGroups.Where(og => og.IsRelational).SelectMany(og => og.OperatorKinds)) { yield return new FilterTestCase() { Filter = "false " + operatorKind.ToOperatorName() + " true", ExpectedFilterCondition = new BinaryOperatorNode(operatorKind, new ConstantNode(false), new ConstantNode(true)) }; } foreach (var operatorKind in QueryTestUtils.BinaryOperatorGroups.Where(og => !og.IsRelational).SelectMany(og => og.OperatorKinds)) { BinaryOperatorNode left = new BinaryOperatorNode(operatorKind, new ConstantNode(1), new ConstantNode(2)); yield return new FilterTestCase() { Filter = "1 " + operatorKind.ToOperatorName() + " 2 le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, left, new ConstantNode(5)) }; } #endregion Single operator #region Two operators from the same group foreach (var operatorGroup in QueryTestUtils.BinaryOperatorGroups.Where(od => od.IsRelational)) { IEnumerable<BinaryOperatorKind[]> operatorPairs = new[] { new BinaryOperatorKind[] { operatorGroup.OperatorKinds[0], operatorGroup.OperatorKinds[0] } }; if (operatorGroup.OperatorKinds.Length > 1) { operatorPairs = operatorPairs.Concat(operatorGroup.OperatorKinds.Variations(2)); } foreach (var operatorPair in operatorPairs) { BinaryOperatorNode left = new BinaryOperatorNode(operatorPair[0], new ConstantNode(true), new ConstantNode(false)); yield return new FilterTestCase() { Filter = "true " + operatorPair[0].ToOperatorName() + " false " + operatorPair[1].ToOperatorName() + " true", ExpectedFilterCondition = new BinaryOperatorNode(operatorPair[1], left, new ConstantNode(true)) }; BinaryOperatorNode right = new BinaryOperatorNode(operatorPair[1], new ConstantNode(false), new ConstantNode(true)); yield return new FilterTestCase() { Filter = "true " + operatorPair[0].ToOperatorName() + " (false " + operatorPair[1].ToOperatorName() + " true)", ExpectedFilterCondition = new BinaryOperatorNode(operatorPair[0], new ConstantNode(true), right) }; } } foreach (var operatorGroup in QueryTestUtils.BinaryOperatorGroups.Where(od => !od.IsRelational)) { IEnumerable<BinaryOperatorKind[]> operatorPairs = new[] { new BinaryOperatorKind[] { operatorGroup.OperatorKinds[0], operatorGroup.OperatorKinds[0] } }; if (operatorGroup.OperatorKinds.Length > 1) { operatorPairs = operatorPairs.Concat(operatorGroup.OperatorKinds.Variations(2)); } foreach (var operatorPair in operatorPairs) { BinaryOperatorNode innerLeft1 = new BinaryOperatorNode(operatorPair[0], new ConstantNode(1), new ConstantNode(2)); BinaryOperatorNode outerLeft1 = new BinaryOperatorNode(operatorPair[1], innerLeft1, new ConstantNode(3)); yield return new FilterTestCase() { Filter = "1 " + operatorPair[0].ToOperatorName() + " 2 " + operatorPair[1].ToOperatorName() + " 3 le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, outerLeft1, new ConstantNode(5)) }; BinaryOperatorNode innerRight2 = new BinaryOperatorNode(operatorPair[1], new ConstantNode(2), new ConstantNode(3)); BinaryOperatorNode outerLeft2 = new BinaryOperatorNode(operatorPair[0], new ConstantNode(1), innerRight2); yield return new FilterTestCase() { Filter = "1 " + operatorPair[0].ToOperatorName() + " (2 " + operatorPair[1].ToOperatorName() + " 3) le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, outerLeft2, new ConstantNode(5)) }; } } #endregion Two operators from the same group #region Two operators from different groups foreach (var operatorGroupHigher in QueryTestUtils.BinaryOperatorGroups.Where(og => og.IsRelational)) { foreach (var operatorGroupLower in QueryTestUtils.BinaryOperatorGroups.Where(og => og.IsRelational && og.Priority > operatorGroupHigher.Priority)) { foreach (var operatorKindHigher in operatorGroupHigher.OperatorKinds) { foreach (var operatorKindLower in operatorGroupLower.OperatorKinds) { BinaryOperatorNode left = new BinaryOperatorNode(operatorKindLower, new ConstantNode(true), new ConstantNode(false)); // Lower and higher yield return new FilterTestCase() { Filter = "true " + operatorKindLower.ToOperatorName() + " false " + operatorKindHigher.ToOperatorName() + " true", ExpectedFilterCondition = new BinaryOperatorNode(operatorKindHigher, left, new ConstantNode(true)) }; // Lower and higher with parentheses BinaryOperatorNode right = new BinaryOperatorNode(operatorKindHigher, new ConstantNode(false), new ConstantNode(true)); yield return new FilterTestCase() { Filter = "true " + operatorKindLower.ToOperatorName() + " (false " + operatorKindHigher.ToOperatorName() + " true)", ExpectedFilterCondition = new BinaryOperatorNode(operatorKindLower, new ConstantNode(true), right) }; BinaryOperatorNode right2 = new BinaryOperatorNode(operatorKindLower, new ConstantNode(false), new ConstantNode(true)); // Higher and lower yield return new FilterTestCase() { Filter = "true " + operatorKindHigher.ToOperatorName() + " false " + operatorKindLower.ToOperatorName() + " true", ExpectedFilterCondition = new BinaryOperatorNode(operatorKindHigher, new ConstantNode(true), right2) }; } } } } foreach (var operatorGroupHigher in QueryTestUtils.BinaryOperatorGroups.Where(og => !og.IsRelational)) { foreach (var operatorGroupLower in QueryTestUtils.BinaryOperatorGroups.Where(og => !og.IsRelational && og.Priority > operatorGroupHigher.Priority)) { foreach (var operatorKindHigher in operatorGroupHigher.OperatorKinds) { foreach (var operatorKindLower in operatorGroupLower.OperatorKinds) { // Lower and higher BinaryOperatorNode innerLeft = new BinaryOperatorNode(operatorKindLower, new ConstantNode(1), new ConstantNode(2)); BinaryOperatorNode outerLeft = new BinaryOperatorNode(operatorKindHigher, innerLeft, new ConstantNode(3)); yield return new FilterTestCase() { Filter = "1 " + operatorKindLower.ToOperatorName() + " 2 " + operatorKindHigher.ToOperatorName() + " 3 le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, outerLeft, new ConstantNode(5)) }; // Lower and higher with parentheses BinaryOperatorNode innerRight = new BinaryOperatorNode(operatorKindHigher, new ConstantNode(2), new ConstantNode(3)); BinaryOperatorNode outerLeft2 = new BinaryOperatorNode(operatorKindLower, new ConstantNode(1), innerRight); yield return new FilterTestCase() { Filter = "1 " + operatorKindLower.ToOperatorName() + " (2 " + operatorKindHigher.ToOperatorName() + " 3) le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, outerLeft2, new ConstantNode(5)) }; // Higher and lower BinaryOperatorNode innerRight2 = new BinaryOperatorNode(operatorKindLower, new ConstantNode(2), new ConstantNode(3)); BinaryOperatorNode outerLeft3 = new BinaryOperatorNode(operatorKindHigher, new ConstantNode(1), innerRight2); yield return new FilterTestCase() { Filter = "1 " + operatorKindHigher.ToOperatorName() + " 2 " + operatorKindLower.ToOperatorName() + " 3 le 5", ExpectedFilterCondition = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, outerLeft3, new ConstantNode(5)) }; } } } } #endregion Two operators from different groups }
private static AllowedArithmeticOperators ToArithmeticOperator(BinaryOperatorNode binaryNode) { AllowedArithmeticOperators result = AllowedArithmeticOperators.None; switch (binaryNode.OperatorKind) { case BinaryOperatorKind.Add: result = AllowedArithmeticOperators.Add; break; case BinaryOperatorKind.Divide: result = AllowedArithmeticOperators.Divide; break; case BinaryOperatorKind.Modulo: result = AllowedArithmeticOperators.Modulo; break; case BinaryOperatorKind.Multiply: result = AllowedArithmeticOperators.Multiply; break; case BinaryOperatorKind.Subtract: result = AllowedArithmeticOperators.Subtract; break; default: // should never be here Contract.Assert(false, "ToArithmeticOperator should never be here."); break; } return result; }
private static void VerifyBinaryOperatorQueryNodesAreEqual(BinaryOperatorNode expected, BinaryOperatorNode actual, AssertionHandler assert) { assert.AreEqual(expected.OperatorKind, actual.OperatorKind, "Operator kinds differ."); VerifyQueryNodesAreEqual(expected.Left, actual.Left, assert); VerifyQueryNodesAreEqual(expected.Right, actual.Right, assert); }
private QueryNode ParseMultiplicative() { QueryNode left = this.ParseUnary(); while (this.lexer.Token.Kind == QueryTokenKind.Multiply || this.lexer.Token.Kind == QueryTokenKind.Divide || this.lexer.Token.Kind == QueryTokenKind.Modulo) { QueryTokenKind opKind = this.lexer.Token.Kind; this.lexer.NextToken(); var right = this.ParseUnary(); switch (opKind) { case QueryTokenKind.Multiply: left = new BinaryOperatorNode(BinaryOperatorKind.Multiply, left, right); break; case QueryTokenKind.Divide: left = new BinaryOperatorNode(BinaryOperatorKind.Divide, left, right); break; case QueryTokenKind.Modulo: left = new BinaryOperatorNode(BinaryOperatorKind.Modulo, left, right); break; } } return left; }
/// <summary> /// Process binary comparison operators. /// </summary> /// <param name="expression"> /// The expression to visit. /// </param> /// <returns> /// The visited expression. /// </returns> private Expression VisitBinary(BinaryExpression expression) { if (expression != null) { // special case for enums, because we send them as strings UnaryExpression enumExpression = null; ConstantExpression constantExpression = null; BinaryExpression stringCompareExpression = null; if (this.CheckEnumExpression(expression, out enumExpression, out constantExpression)) { this.Visit(this.RewriteEnumExpression(enumExpression, (ConstantExpression)expression.Right, expression.NodeType)); } // special case concat as it's OData function isn't infix else if (expression.NodeType == ExpressionType.Add && expression.Left.Type == typeof(string) && expression.Right.Type == typeof(string)) { //rewrite addition into a call to concat, instead of duplicating generation code. this.Visit(this.RewriteStringAddition(expression)); } // special case for string comparisons emitted by the VB compiler else if (this.CheckVBStringCompareExpression(expression, out stringCompareExpression)) { this.Visit(stringCompareExpression); } else { BinaryOperatorKind operatorKind; switch (expression.NodeType) { case ExpressionType.AndAlso: case ExpressionType.And: operatorKind = BinaryOperatorKind.And; break; case ExpressionType.Or: case ExpressionType.OrElse: operatorKind = BinaryOperatorKind.Or; break; case ExpressionType.Equal: operatorKind = BinaryOperatorKind.Equal; break; case ExpressionType.NotEqual: operatorKind = BinaryOperatorKind.NotEqual; break; case ExpressionType.LessThan: operatorKind = BinaryOperatorKind.LessThan; break; case ExpressionType.LessThanOrEqual: operatorKind = BinaryOperatorKind.LessThanOrEqual; break; case ExpressionType.GreaterThan: operatorKind = BinaryOperatorKind.GreaterThan; break; case ExpressionType.GreaterThanOrEqual: operatorKind = BinaryOperatorKind.GreaterThanOrEqual; break; case ExpressionType.Add: operatorKind = BinaryOperatorKind.Add; break; case ExpressionType.Subtract: operatorKind = BinaryOperatorKind.Subtract; break; case ExpressionType.Multiply: operatorKind = BinaryOperatorKind.Multiply; break; case ExpressionType.Divide: operatorKind = BinaryOperatorKind.Divide; break; case ExpressionType.Modulo: operatorKind = BinaryOperatorKind.Modulo; break; default: throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, "The operator '{0}' is not supported in the 'Where' Mobile Services query expression '{1}'.", expression.NodeType, expression.ToString())); } var node = new BinaryOperatorNode(operatorKind, null, null); this.filterExpression.Push(node); this.Visit(expression.Left); this.Visit(expression.Right); this.SetChildren(node); } } return expression; }
private QueryNode ParseComparison() { QueryNode left = this.ParseAdditive(); while (this.lexer.Token.Kind == QueryTokenKind.Equal || this.lexer.Token.Kind == QueryTokenKind.NotEqual || this.lexer.Token.Kind == QueryTokenKind.GreaterThan || this.lexer.Token.Kind == QueryTokenKind.GreaterThanEqual || this.lexer.Token.Kind == QueryTokenKind.LessThan || this.lexer.Token.Kind == QueryTokenKind.LessThanEqual) { QueryTokenKind opKind = this.lexer.Token.Kind; this.lexer.NextToken(); QueryNode right = this.ParseAdditive(); switch (opKind) { case QueryTokenKind.Equal: left = new BinaryOperatorNode(BinaryOperatorKind.Equal, left, right); break; case QueryTokenKind.NotEqual: left = new BinaryOperatorNode(BinaryOperatorKind.NotEqual, left, right); break; case QueryTokenKind.GreaterThan: left = new BinaryOperatorNode(BinaryOperatorKind.GreaterThan, left, right); break; case QueryTokenKind.GreaterThanEqual: left = new BinaryOperatorNode(BinaryOperatorKind.GreaterThanOrEqual, left, right); break; case QueryTokenKind.LessThan: left = new BinaryOperatorNode(BinaryOperatorKind.LessThan, left, right); break; case QueryTokenKind.LessThanEqual: left = new BinaryOperatorNode(BinaryOperatorKind.LessThanOrEqual, left, right); break; } } return left; }
private static Uri BuildNavigationNextPageLink(ODataResource entry, ExpandedNavigationSelectItem expandedNavigationSelectItem) { var segment = (NavigationPropertySegment)expandedNavigationSelectItem.PathToNavigationProperty.LastSegment; ResourceRangeVariableReferenceNode refNode = OeGetParser.CreateRangeVariableReferenceNode((IEdmEntitySet)segment.NavigationSource); IEdmNavigationProperty navigationProperty = segment.NavigationProperty; var keys = new List <KeyValuePair <IEdmStructuralProperty, Object> >(); if (navigationProperty.IsPrincipal()) { IEnumerator <IEdmStructuralProperty> dependentProperties = navigationProperty.Partner.DependentProperties().GetEnumerator(); foreach (IEdmStructuralProperty key in navigationProperty.Partner.PrincipalProperties()) { foreach (ODataProperty property in entry.Properties) { if (property.Name == key.Name) { dependentProperties.MoveNext(); keys.Add(new KeyValuePair <IEdmStructuralProperty, Object>(dependentProperties.Current, property.Value)); break; } } } } else { IEnumerator <IEdmStructuralProperty> principalProperties = navigationProperty.PrincipalProperties().GetEnumerator(); foreach (IEdmStructuralProperty key in navigationProperty.DependentProperties()) { foreach (ODataProperty property in entry.Properties) { if (property.Name == key.Name) { principalProperties.MoveNext(); keys.Add(new KeyValuePair <IEdmStructuralProperty, Object>(principalProperties.Current, property.Value)); break; } } } } BinaryOperatorNode filterExpression = OeGetParser.CreateFilterExpression(refNode, keys); if (expandedNavigationSelectItem.FilterOption != null) { filterExpression = new BinaryOperatorNode(BinaryOperatorKind.And, filterExpression, expandedNavigationSelectItem.FilterOption.Expression); } var segments = new ODataPathSegment[] { new EntitySetSegment((IEdmEntitySet)refNode.NavigationSource) }; var odataUri = new ODataUri() { Path = new ODataPath(segments), Filter = new FilterClause(filterExpression, refNode.RangeVariable), OrderBy = expandedNavigationSelectItem.OrderByOption, SelectAndExpand = expandedNavigationSelectItem.SelectAndExpand, Top = expandedNavigationSelectItem.TopOption, Skip = expandedNavigationSelectItem.SkipOption, QueryCount = expandedNavigationSelectItem.CountOption }; return(odataUri.BuildUri(ODataUrlKeyDelimiter.Parentheses)); }