/// <summary> /// Create a GroupByPropertyNode. /// </summary> /// <param name="name">The name of this node.</param> /// <param name="expression">The <see cref="SingleValueNode"/> of this node.</param> public GroupByPropertyNode(string name, SingleValueNode expression) { ExceptionUtils.CheckArgumentNotNull(name, "name"); this.Name = name; this.Expression = expression; }
/// <summary> /// Create a GroupByPropertyNode. /// </summary> /// <param name="name">The name of this node.</param> /// <param name="accessor">The <see cref="SingleValueNode"/> of this node.</param> public GroupByPropertyNode(string name, SingleValueNode accessor) { ExceptionUtils.CheckArgumentNotNull(name, "name"); this.Name = name; this.Accessor = accessor; }
/// <summary> /// Generates a bound query node representing an <see cref="IEdmProperty"/> given an already semantically bound parent node. /// </summary> /// <param name="parentNode">The semantically bound source node of this end path token</param> /// <param name="property">The <see cref="IEdmProperty"/> that will be bound to this node. Must not be primitive collection</param> /// <returns>QueryNode bound to this property.</returns> internal static QueryNode GeneratePropertyAccessQueryNode(SingleValueNode parentNode, IEdmProperty property) { ExceptionUtils.CheckArgumentNotNull(parentNode, "parent"); ExceptionUtils.CheckArgumentNotNull(property, "property"); // TODO: Remove this check. // We should verify that the top level of an expression is a bool rather than arbitrarily restrict property types. // We can get here if there is a query like $filter=MyCollectionProperty eq 'foo' or something. // If it was $filter=MyCollectionProperty/any(...) then we would have gone down the 'NonRootSegment' code path instead of this one if (property.Type.IsNonEntityCollectionType()) { // if this happens to be a top level node (i.e. $filter=MyCollection), then it will fail further up the chain, so // don't need to worry about checking for that here. return new CollectionPropertyAccessNode(parentNode, property); } if (property.PropertyKind == EdmPropertyKind.Navigation) { // These are error cases in practice, but we let ourselves throw later for better context-sensitive error messages var edmNavigationProperty = (IEdmNavigationProperty)property; var singleEntityParentNode = (SingleEntityNode)parentNode; if (edmNavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { return new CollectionNavigationNode(edmNavigationProperty, singleEntityParentNode); } return new SingleNavigationNode(edmNavigationProperty, singleEntityParentNode); } return new SingleValuePropertyAccessNode(parentNode, property); }
public ParameterAliasNodeTranslatorTest() { var builder = new ODataConventionModelBuilder(); builder.EntitySet<ParameterAliasCustomer>("Customers"); builder.EntitySet<ParameterAliasOrder>("Orders"); builder.EntityType<ParameterAliasCustomer>().Function("CollectionFunctionCall") .ReturnsCollection<int>().Parameter<int>("p1"); builder.EntityType<ParameterAliasCustomer>().Function("EntityCollectionFunctionCall") .ReturnsCollectionFromEntitySet<ParameterAliasCustomer>("Customers").Parameter<int>("p1"); builder.EntityType<ParameterAliasCustomer>().Function("SingleEntityFunctionCall") .Returns<ParameterAliasCustomer>().Parameter<int>("p1"); builder.EntityType<ParameterAliasCustomer>().Function("SingleEntityFunctionCallWithoutParameters") .Returns<ParameterAliasCustomer>(); builder.EntityType<ParameterAliasCustomer>().Function("SingleValueFunctionCall") .Returns<int>().Parameter<int>("p1"); _model = builder.GetEdmModel(); _customersEntitySet = _model.FindDeclaredEntitySet("Customers"); _customerEntityType = _customersEntitySet.EntityType(); _parameterAliasMappedNode = new ConstantNode(123); }
/// <summary> /// Creates a <see cref="FilterClause"/>. /// </summary> /// <param name="expression">The filter expression - this should evaluate to a single boolean value. Cannot be null.</param> /// <param name="rangeVariable">The parameter for the expression which represents a single value from the collection. Cannot be null.</param> /// <exception cref="System.ArgumentNullException">Throws if the input expression or rangeVariable is null.</exception> public FilterClause(SingleValueNode expression, RangeVariable rangeVariable) { ExceptionUtils.CheckArgumentNotNull(expression, "expression"); ExceptionUtils.CheckArgumentNotNull(rangeVariable, "parameter"); this.expression = expression; this.rangeVariable = rangeVariable; }
public override void PromoteBinaryOperandTypes( BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { stringAsEnum.PromoteBinaryOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode, out typeReference); }
/// <summary> /// Promote the left and right operand types /// </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 virtual void PromoteBinaryOperandTypes( BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { typeReference = null; BinaryOperatorBinder.PromoteOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode); }
/// <summary> /// Creates an <see cref="OrderByClause"/>. /// </summary> /// <param name="thenBy">The next orderby to perform after performing this orderby, can be null in the case of only a single orderby expression.</param> /// <param name="expression">The order-by expression. Cannot be null.</param> /// <param name="direction">The direction to order.</param> /// <param name="rangeVariable">The rangeVariable for the expression which represents a single value from the collection we iterate over. </param> /// <exception cref="System.ArgumentNullException">Throws if the input expression or rangeVariable is null.</exception> public OrderByClause(OrderByClause thenBy, SingleValueNode expression, OrderByDirection direction, RangeVariable rangeVariable) { ExceptionUtils.CheckArgumentNotNull(expression, "expression"); ExceptionUtils.CheckArgumentNotNull(rangeVariable, "parameter"); this.thenBy = thenBy; this.expression = expression; this.direction = direction; this.rangeVariable = rangeVariable; }
/// <summary> /// Ensures that the parent node is of entity type, throwing if it is not. /// </summary> /// <param name="parent">Parent node to a navigation property.</param> /// <returns>The given parent node as a SingleEntityNode.</returns> internal static SingleEntityNode EnsureParentIsEntityForNavProp(SingleValueNode parent) { ExceptionUtils.CheckArgumentNotNull(parent, "parent"); SingleEntityNode parentEntity = parent as SingleEntityNode; if (parentEntity == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_NavigationPropertyNotFollowingSingleEntityType); } return parentEntity; }
/// <summary> /// Create a AggregateExpression. /// </summary> /// <param name="expression">The aggregation expression.</param> /// <param name="method">The <see cref="AggregationMethod"/>.</param> /// <param name="alias">The aggregation alias.</param> /// <param name="typeReference">The <see cref="IEdmTypeReference"/> of this aggregate expression.</param> public AggregateExpression(SingleValueNode expression, AggregationMethod method, string alias, IEdmTypeReference typeReference) { ExceptionUtils.CheckArgumentNotNull(expression, "expression"); ExceptionUtils.CheckArgumentNotNull(alias, "alias"); ExceptionUtils.CheckArgumentNotNull(typeReference, "typeReference"); this.expression = expression; this.method = method; this.alias = alias; this.typeReference = typeReference; }
/// <summary> /// Get the promoted type reference of the operand /// </summary> /// <param name="operand">the operand</param> /// <param name="unaryOperatorKind">the operator kind</param> /// <returns>the type reference of the operand</returns> private static IEdmTypeReference PromoteOperandType(SingleValueNode operand, UnaryOperatorKind unaryOperatorKind) { IEdmTypeReference typeReference = operand.TypeReference; if (!TypePromotionUtils.PromoteOperandType(unaryOperatorKind, ref typeReference)) { string typeName = operand.TypeReference == null ? "<null>" : operand.TypeReference.ODataFullName(); throw new ODataException(ODataErrorStrings.MetadataBinder_IncompatibleOperandError(typeName, unaryOperatorKind)); } return typeReference; }
/// <summary> /// This method generates a <see cref="SingleValueOpenPropertyAccessNode"/> for properties of open type /// </summary> /// <param name="endPathToken">EndPathToken to bind into an open property node.</param> /// <param name="parentNode">Parent node of this open property</param> /// <returns>Will return a <see cref="SingleValueOpenPropertyAccessNode"/> when open types are supported</returns> internal static SingleValueOpenPropertyAccessNode GeneratePropertyAccessQueryForOpenType(EndPathToken endPathToken, SingleValueNode parentNode) { if (parentNode.TypeReference != null && !parentNode.TypeReference.Definition.IsOpenType()) { throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared( parentNode.TypeReference.FullName(), endPathToken.Identifier)); } return new SingleValueOpenPropertyAccessNode(parentNode, endPathToken.Identifier); }
public void OrOperatorShouldResultInBinaryOperatorNode() { this.leftParameterSingleValueQueryNode = new ConstantNode(false); this.rightParameterSingleValueQueryNode = new ConstantNode(true); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.Or, new LiteralToken(false), new LiteralToken(true)); var resultNode = this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); resultNode.ShouldBeBinaryOperatorNode(BinaryOperatorKind.Or).And.TypeReference.PrimitiveKind().Should().Be(EdmPrimitiveTypeKind.Boolean); resultNode.As<BinaryOperatorNode>().Left.ShouldBeConstantQueryNode(false); resultNode.As<BinaryOperatorNode>().Right.ShouldBeConstantQueryNode(true); }
public void AndOperatorCompatibleTypeShouldResultInBinaryOperatorNode() { this.leftParameterSingleValueQueryNode = new UnaryOperatorNode(UnaryOperatorKind.Negate, new UnaryOperatorNode(UnaryOperatorKind.Not, new ConstantNode(null))); this.rightParameterSingleValueQueryNode = new SingleValueFunctionCallNode("func", null, EdmCoreModel.Instance.GetBoolean(false)); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.And, new LiteralToken("foo"), new LiteralToken("bar")); var resultNode = this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); resultNode.ShouldBeBinaryOperatorNode(BinaryOperatorKind.And).And.TypeReference.PrimitiveKind().Should().Be(EdmPrimitiveTypeKind.Boolean); resultNode.As<BinaryOperatorNode>().Left.ShouldBeConvertQueryNode(EdmPrimitiveTypeKind.Boolean); resultNode.As<BinaryOperatorNode>().Right.ShouldBeConvertQueryNode(EdmPrimitiveTypeKind.Boolean); }
/// <summary> /// Create a AggregateStatement. /// </summary> /// <param name="expression">The aggregation expression.</param> /// <param name="withVerb">The <see cref="AggregationVerb"/>.</param> /// <param name="from">The aggregation from <see cref="SingleValuePropertyAccessNode"/>.</param> /// <param name="alias">The aggregation alias.</param> /// <param name="typeReference">The <see cref="IEdmTypeReference"/> of this aggregate statement.</param> public AggregateStatement(SingleValueNode expression, AggregationVerb withVerb, SingleValuePropertyAccessNode from, string alias, IEdmTypeReference typeReference) { ExceptionUtils.CheckArgumentNotNull(expression, "expression"); ExceptionUtils.CheckArgumentNotNull(alias, "alias"); ExceptionUtils.CheckArgumentNotNull(typeReference, "typeReference"); this.expression = expression; this.withVerb = withVerb; this.from = from; this.alias = alias; this.typeReference = typeReference; }
/// <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> internal static void PromoteOperandTypes(BinaryOperatorKind binaryOperatorKind, ref SingleValueNode left, ref SingleValueNode right) { IEdmTypeReference leftType; IEdmTypeReference rightType; if (!TypePromotionUtils.PromoteOperandTypes(binaryOperatorKind, left, right, out leftType, out rightType)) { 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); }
/// <summary> /// Constructs a new <see cref="CollectionPropertyAccessNode"/>. /// </summary> /// <param name="source">The value containing the property.</param> /// <param name="property">The EDM property which is to be accessed.</param> /// <exception cref="System.ArgumentNullException">Throws if the input source or property is null.</exception> /// <exception cref="ArgumentException">Throws if the input property is not a collection of structural properties</exception> public CollectionPropertyAccessNode(SingleValueNode source, IEdmProperty property) { ExceptionUtils.CheckArgumentNotNull(source, "source"); ExceptionUtils.CheckArgumentNotNull(property, "property"); if (property.PropertyKind != EdmPropertyKind.Structural) { throw new ArgumentException(ODataErrorStrings.Nodes_PropertyAccessShouldBeNonEntityProperty(property.Name)); } if (!property.Type.IsCollection()) { throw new ArgumentException(ODataErrorStrings.Nodes_PropertyAccessTypeMustBeCollection(property.Name)); } this.source = source; this.property = property; this.collectionTypeReference = property.Type.AsCollection(); this.itemType = this.collectionTypeReference.ElementType(); }
/// <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; }
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); }
/// <summary> /// Translate parameter alias node to corresponding single value node. /// </summary> /// <param name="node">The node to be translated.</param> /// <param name="parameterAliasNodes">The parameter alias node mapping.</param> /// <returns>The translated node.</returns> public static Semantic.SingleValueNode TranslateParameterAlias( Semantic.SingleValueNode node, IDictionary <string, Semantic.SingleValueNode> parameterAliasNodes) { if (node == null) { throw Error.ArgumentNull("node"); } if (parameterAliasNodes == null) { throw Error.ArgumentNull("parameterAliasNodes"); } Semantic.ParameterAliasNode parameterAliasNode = node as Semantic.ParameterAliasNode; if (parameterAliasNode == null) { return(node); } Semantic.SingleValueNode singleValueNode; if (parameterAliasNodes.TryGetValue(parameterAliasNode.Alias, out singleValueNode) && singleValueNode != null) { if (singleValueNode is Semantic.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> /// 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); }
public void AndOperatorNullLiteralShouldResultInBinaryOperatorNodeWithConvert() { this.leftParameterSingleValueQueryNode = new ConstantNode(null); this.rightParameterSingleValueQueryNode = new SingleValueFunctionCallNode(FuncName, null, EdmCoreModel.Instance.GetBoolean(false)); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.And, new LiteralToken("foo"), new LiteralToken("bar")); var resultNode = this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); var binaryNode = resultNode.ShouldBeBinaryOperatorNode(BinaryOperatorKind.And).And; binaryNode.TypeReference.IsNullable.Should().BeTrue(); var left = binaryNode.Left.ShouldBeConvertQueryNode(EdmPrimitiveTypeKind.Boolean).And; left.TypeReference.IsNullable.Should().BeTrue(); left.Source.ShouldBeConstantQueryNode<object>(null); var right = binaryNode.Right.ShouldBeConvertQueryNode(EdmPrimitiveTypeKind.Boolean).And; right.TypeReference.IsNullable.Should().BeTrue(); right.Source.ShouldBeSingleValueFunctionCallQueryNode(FuncName); }
private Expression BindAccessor(SingleValueNode node) { switch (node.Kind) { case QueryNodeKind.EntityRangeVariableReference: return this._lambdaParameter; case QueryNodeKind.SingleValuePropertyAccess: var propAccessNode = node as SingleValuePropertyAccessNode; return CreatePropertyAccessExpression(BindAccessor(propAccessNode.Source), propAccessNode.Property); case QueryNodeKind.SingleValueOpenPropertyAccess: var openNode = node as SingleValueOpenPropertyAccessNode; return Expression.Property(BindAccessor(openNode.Source), openNode.Name); 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); } }
/// <summary> /// Create a BinaryOperatorNode /// </summary> /// <param name="operatorKind">The binary operator type.</param> /// <param name="left">The left operand.</param> /// <param name="right">The right operand.</param> /// <exception cref="System.ArgumentNullException">Throws if the left or right inputs are null.</exception> /// <exception cref="ODataException">Throws if the two operands don't have the same type.</exception> public BinaryOperatorNode(BinaryOperatorKind operatorKind, SingleValueNode left, SingleValueNode right) : this(operatorKind, left, right, /*typeReference*/ null) { }
public void LeftTokenTypeImcompatibleWithRightTokenShouldFail() { this.leftParameterSingleValueQueryNode = new ConstantNode(true); this.rightParameterSingleValueQueryNode = new ConstantNode(1); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.Equal, new LiteralToken("foo"), new LiteralToken("bar")); Action bind = () => this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); bind.ShouldThrow<ODataException>(). WithMessage((Strings.MetadataBinder_IncompatibleOperandsError("Edm.Boolean", "Edm.Int32", BinaryOperatorKind.Equal))); }
public void RightTokenTypeImcompatibleWithOperatorShouldFail() { this.leftParameterSingleValueQueryNode = new ConstantNode(999); this.rightParameterSingleValueQueryNode = new ConstantNode(string.Empty); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.Multiply, new LiteralToken("foo"), new LiteralToken("bar")); Action bind = () => this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); bind.ShouldThrow<ODataException>(). WithMessage((Strings.MetadataBinder_IncompatibleOperandsError("Edm.Int32", "Edm.String", BinaryOperatorKind.Multiply))); }
public void LeftTokenTypeIncompatibleWithOperatorAndRightTokenOpenPropertyShouldFail() { this.leftParameterSingleValueQueryNode = new ConstantNode(DateTimeOffset.Now); this.rightParameterSingleValueQueryNode = new SingleValueOpenPropertyAccessNode(new ConstantNode(null), "SomeProperty"); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.And, new LiteralToken("foo"), new LiteralToken("bar")); Action bind = () => this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); bind.ShouldThrow<ODataException>(). WithMessage((Strings.MetadataBinder_IncompatibleOperandsError("Edm.DateTimeOffset", "<null>", BinaryOperatorKind.And))); }
public void GreaterThanOrEqualOperatorShouldResultInBinaryOperatorNode() { this.leftParameterSingleValueQueryNode = new ConstantNode(99); this.rightParameterSingleValueQueryNode = new ConstantNode(99.1); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.GreaterThanOrEqual, new LiteralToken("foo"), new LiteralToken("bar")); var resultNode = this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); resultNode.ShouldBeBinaryOperatorNode(BinaryOperatorKind.GreaterThanOrEqual).And.TypeReference.PrimitiveKind().Should().Be(EdmPrimitiveTypeKind.Boolean); resultNode.As<BinaryOperatorNode>().Left.ShouldBeConstantQueryNode(99d); resultNode.As<BinaryOperatorNode>().Right.ShouldBeConstantQueryNode(99.1); }
/// <summary> /// Create a GroupByPropertyNode. /// </summary> /// <param name="name">The name of this node.</param> /// <param name="expression">The <see cref="SingleValueNode"/> of this node.</param> /// <param name="type">The <see cref="IEdmTypeReference"/> of this node.</param> public GroupByPropertyNode(string name, SingleValueNode expression, IEdmTypeReference type) : this(name, expression) { this.typeReference = type; }
public void AndOperatorNullAndOpenPropertyShouldResultInBinaryOperatorNodeWithNullType() { this.leftParameterSingleValueQueryNode = new ConstantNode(null); this.rightParameterSingleValueQueryNode = new SingleValueOpenPropertyAccessNode(new ConstantNode(null), OpenPropertyName); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.And, new LiteralToken("foo"), new LiteralToken("bar")); var resultNode = this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); var binaryNode = resultNode.ShouldBeBinaryOperatorNode(BinaryOperatorKind.And).And; binaryNode.TypeReference.Should().BeNull(); binaryNode.Left.ShouldBeConstantQueryNode<object>(null); binaryNode.Right.ShouldBeSingleValueOpenPropertyAccessQueryNode(OpenPropertyName); }
/// <summary> /// Create a BinaryOperatorNode /// </summary> /// <param name="operatorKind">The binary operator type.</param> /// <param name="left">The left operand.</param> /// <param name="right">The right operand.</param> /// <exception cref="System.ArgumentNullException">Throws if the left or right inputs are null.</exception> /// <exception cref="ODataException">Throws if the two operands don't have the same type.</exception> public BinaryOperatorNode(BinaryOperatorKind operatorKind, SingleValueNode left, SingleValueNode right) { ExceptionUtils.CheckArgumentNotNull(left, "left"); ExceptionUtils.CheckArgumentNotNull(right, "right"); this.operatorKind = operatorKind; this.left = left; this.right = right; // set the TypeReerence based on the Operands. if (this.Left == null || this.Right == null || this.Left.TypeReference == null || this.Right.TypeReference == null) { this.typeReference = null; } else { // Ensure that both operands have the same type if (!this.Left.TypeReference.Definition.IsEquivalentTo(this.Right.TypeReference.Definition)) { throw new ODataException( ODataErrorStrings.BinaryOperatorQueryNode_OperandsMustHaveSameTypes( this.Left.TypeReference.ODataFullName(), this.Right.TypeReference.ODataFullName())); } // Get a primitive type reference; this must not fail since we checked that the type is of kind 'primitive'. IEdmPrimitiveTypeReference primitiveOperatorTypeReference = this.Left.TypeReference.AsPrimitive(); this.typeReference = QueryNodeUtils.GetBinaryOperatorResultType(primitiveOperatorTypeReference, this.OperatorKind); } }
public override void PromoteBinaryOperandTypes(BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { _stringAsEnum.PromoteBinaryOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode, out typeReference); }
/// <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) { // TODO 1577: remove this and add it to switch, once the ODataLib v4 EnumNode.Kind bug is fixed. EnumNode enumNode = node as EnumNode; if (enumNode != null) { ValidateEnumNode(enumNode, settings); return; } 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; } }
/// <summary> /// Create a BinaryOperatorNode /// </summary> /// <param name="operatorKind">The binary operator type.</param> /// <param name="left">The left operand.</param> /// <param name="right">The right operand.</param> /// <param name="typeReference">The result typeReference.</param> /// <exception cref="System.ArgumentNullException">Throws if the left or right inputs are null.</exception> internal BinaryOperatorNode(BinaryOperatorKind operatorKind, SingleValueNode left, SingleValueNode right, IEdmTypeReference typeReference) { ExceptionUtils.CheckArgumentNotNull(left, "left"); ExceptionUtils.CheckArgumentNotNull(right, "right"); this.operatorKind = operatorKind; this.left = left; this.right = right; // set the TypeReference if explictly given, otherwise based on the Operands. if (typeReference != null) { this.typeReference = typeReference; } else if (this.Left == null || this.Right == null || this.Left.TypeReference == null || this.Right.TypeReference == null) { this.typeReference = null; } else { // Get a primitive type reference; this must not fail since we checked that the type is of kind 'primitive'. IEdmPrimitiveTypeReference leftType = this.Left.TypeReference.AsPrimitive(); IEdmPrimitiveTypeReference rightType = this.Right.TypeReference.AsPrimitive(); this.typeReference = QueryNodeUtils.GetBinaryOperatorResultType(leftType, rightType, this.OperatorKind); } }
public void ModuloOperatorShouldResultInBinaryOperatorNode() { this.leftParameterSingleValueQueryNode = new ConstantNode(-9.9); this.rightParameterSingleValueQueryNode = new ConstantNode(-100.9); var binaryOperatorQueryToken = new BinaryOperatorToken(BinaryOperatorKind.Modulo, new LiteralToken("foo"), new LiteralToken("bar")); var resultNode = this.binaryOperatorBinder.BindBinaryOperator(binaryOperatorQueryToken); resultNode.ShouldBeBinaryOperatorNode(BinaryOperatorKind.Modulo).And.TypeReference.PrimitiveKind().Should().Be(EdmPrimitiveTypeKind.Double); resultNode.As<BinaryOperatorNode>().Left.ShouldBeConstantQueryNode(-9.9); resultNode.As<BinaryOperatorNode>().Right.ShouldBeConstantQueryNode(-100.9); }
/// <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; } }
/// <summary> /// Created a SingleValueCastNode with the given source node and the given type to cast to. /// </summary> /// <param name="source"> Source <see cref="SingleValueNode"/> that is being cast.</param> /// <param name="complexType">Type to cast to.</param> /// <exception cref="System.ArgumentNullException">Throws if the input complexType is null.</exception> public SingleValueCastNode(SingleValueNode source, IEdmComplexType complexType) { ExceptionUtils.CheckArgumentNotNull(complexType, "complexType"); this.source = source; this.typeReference = new EdmComplexTypeReference(complexType, false); }