private static void VerifyGroupByTokenProperties(IEnumerable <string> expectedEndPathIdentifiers, GroupByToken actual) { actual.Should().NotBeNull(); if (expectedEndPathIdentifiers == null || !expectedEndPathIdentifiers.Any()) { actual.Properties.Should().HaveCount(0); } else { actual.Properties.Should().HaveCount(expectedEndPathIdentifiers.Count()); List <string> expectedIdentifierList = expectedEndPathIdentifiers.ToList(); int i = 0; foreach (EndPathToken actualProperty in actual.Properties) { actualProperty.Should().NotBeNull(); EndPathToken endPathToken = actualProperty as EndPathToken; endPathToken.Should().NotBeNull(); endPathToken.Identifier.Should().Be(expectedIdentifierList[i]); i++; } } }
public void PropertyAccessQueryTokenDefaultTest() { EndPathToken endPath = new EndPathToken("something", null); this.Assert.AreEqual(QueryTokenKind.EndPath, endPath.Kind, "The InternalKind property has an unexpected value."); this.Assert.AreEqual("something", endPath.Identifier, "The Name property has an unexpected value."); this.Assert.IsNull(endPath.NextToken, "The NextToken property should be null."); }
public void PropertyAccessOnDateCollectionWorks() { var token = new EndPathToken("MyDates", null); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeCollectionPropertyAccessQueryNode(HardCodedTestModel.GetPersonMyDatesProp()); }
public void NestedGroupbyTransformationsInExpandIsAllowed() { // Arrange & Act ExpandTermToken expandTerm = this.ParseExpandOptions("($apply=groupby((Customer/CountryRegion,Product/Name),aggregate(Amount with sum as Total)))"); // Assert Assert.NotNull(expandTerm); Assert.NotNull(expandTerm.ApplyOptions); QueryToken token = Assert.Single(expandTerm.ApplyOptions); GroupByToken groupBy = Assert.IsType <GroupByToken>(token); Assert.Equal(2, groupBy.Properties.Count()); QueryToken queryToken = groupBy.Properties.ElementAt(0); EndPathToken pathToken = queryToken.ShouldBeEndPathToken("CountryRegion"); pathToken.NextToken.ShouldBeInnerPathToken("Customer"); queryToken = groupBy.Properties.ElementAt(1); pathToken = queryToken.ShouldBeEndPathToken("Name"); pathToken.NextToken.ShouldBeInnerPathToken("Product"); Assert.NotNull(groupBy.Child); AggregateToken aggregate = Assert.IsType <AggregateToken>(groupBy.Child); AggregateExpressionToken aggregateExpressionToken = Assert.Single(aggregate.Expressions); Assert.Equal("Total", aggregateExpressionToken.Alias); Assert.Equal(AggregationMethod.Sum, aggregateExpressionToken.Method); aggregateExpressionToken.Expression.ShouldBeEndPathToken("Amount"); }
public void PropertyAccessOnDateTimeOffsetWorks() { var token = new EndPathToken("Birthdate", null); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPersonBirthdateProp()); }
public void BoundFunctionWorks() { var token = new EndPathToken("Fully.Qualified.Namespace.HasJob", null); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeSingleValueFunctionCallQueryNode(HardCodedTestModel.GetFunctionForHasJob()); }
public void PropertyAccessOnTimeOfDayWorks() { var token = new EndPathToken("MyTimeOfDay", null); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPersonMyTimeOfDayProp()); }
public void ShouldThrowIfParameterIsNotInScope() { var token = new EndPathToken("Color", new RangeVariableToken("notInScope")); Action bind = () => this.propertyBinder.BindEndPath(token); bind.ShouldThrow <ODataException>().WithMessage(Strings.MetadataBinder_ParameterNotInScope("notInScope")); }
public void ShouldThrowIfParameterIsNotInScope() { var token = new EndPathToken("Color", new RangeVariableToken("notInScope")); Action bind = () => this.propertyBinder.BindEndPath(token); bind.ShouldThrow<ODataException>().WithMessage(Strings.MetadataBinder_ParameterNotInScope("notInScope")); }
public void NestedGroupbyTransformationsIsAllowed() { var result = this.ParseExpandOptions("($apply=groupby((Customer/CountryRegion,Product/Name),aggregate(Amount with sum as Total)))"); result.Should().NotBeNull(); QueryToken token = result.ApplyOptions.Single(); token.Should().BeOfType <GroupByToken>(); GroupByToken groupBy = token as GroupByToken; groupBy.Properties.Should().HaveCount(2); QueryToken queryToken = groupBy.Properties.ElementAt(0); EndPathToken pathToken = queryToken.ShouldBeEndPathToken("CountryRegion"); pathToken.NextToken.ShouldBeInnerPathToken("Customer"); queryToken = groupBy.Properties.ElementAt(1); pathToken = queryToken.ShouldBeEndPathToken("Name"); pathToken.NextToken.ShouldBeInnerPathToken("Product"); groupBy.Child.Should().NotBeNull(); groupBy.Child.Should().BeOfType <AggregateToken>(); AggregateToken aggregate = groupBy.Child as AggregateToken; AggregateExpressionToken aggregateExpressionToken = aggregate.Expressions.Single(); aggregateExpressionToken.Alias.Should().Equals("Total"); aggregateExpressionToken.Method.Should().Equals(AggregationMethod.Sum); aggregateExpressionToken.Expression.ShouldBeEndPathToken("Amount"); }
private static void VerifyGroupByTokenProperties(IEnumerable <string> expectedEndPathIdentifiers, GroupByToken actual) { Assert.NotNull(actual); if (expectedEndPathIdentifiers == null || !expectedEndPathIdentifiers.Any()) { Assert.Empty(actual.Properties); } else { Assert.Equal(actual.Properties.Count(), expectedEndPathIdentifiers.Count()); List <string> expectedIdentifierList = expectedEndPathIdentifiers.ToList(); int i = 0; foreach (EndPathToken actualProperty in actual.Properties) { Assert.NotNull(actualProperty); EndPathToken endPathToken = actualProperty as EndPathToken; Assert.NotNull(endPathToken); Assert.Equal(endPathToken.Identifier, expectedIdentifierList[i]); i++; } } }
public void ImplicitPropertyAccessShouldCreatePropertyAccessQueryNode() { var token = new EndPathToken("Shoe", null); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPersonShoeProp()). And.Source.ShouldBeEntityRangeVariableReferenceNode(ExpressionConstants.It); }
public void OpenPropertyIsNotBoundToAFunction() { var token = new EndPathToken("SomeOpenProperty", null); BindingState state = GetBindingStateForTest(HardCodedTestModel.GetPaintingTypeReference(), HardCodedTestModel.GetPaintingsSet()); EndPathBinder binder = new EndPathBinder(BindMethod, state); var result = binder.BindEndPath(token); result.ShouldBeSingleValueOpenPropertyAccessQueryNode("SomeOpenProperty"); }
public static EndPathToken ShouldBeEndPathToken(this QueryToken token, string expectedName) { Assert.NotNull(token); EndPathToken propertyAccessQueryToken = Assert.IsType <EndPathToken>(token); Assert.Equal(QueryTokenKind.EndPath, propertyAccessQueryToken.Kind); Assert.Equal(expectedName, propertyAccessQueryToken.Identifier); return(propertyAccessQueryToken); }
public void ExplicitPropertyAccessShouldCreatePropertyAccessQueryNode() { var token = new EndPathToken("Color", new RangeVariableToken("a")); EntityCollectionNode entityCollectionNode = new EntitySetNode(HardCodedTestModel.GetDogsSet()); this.bindingState.RangeVariables.Push(new EntityRangeVariable("a", HardCodedTestModel.GetDogTypeReference(), entityCollectionNode)); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetDogColorProp()). And.Source.ShouldBeEntityRangeVariableReferenceNode("a"); }
public void ShouldThrowNotImplementedIfTypeIsOpen() { const string OpenPropertyName = "Style"; var token = new EndPathToken(OpenPropertyName, new RangeVariableToken("a")); EntityCollectionNode entityCollectionNode = new EntitySetNode(HardCodedTestModel.GetPaintingsSet()); SingleValueNode parentNode = new EntityRangeVariableReferenceNode("a", new EntityRangeVariable("a", HardCodedTestModel.GetPaintingTypeReference(), entityCollectionNode)); var propertyNode = EndPathBinder.GeneratePropertyAccessQueryForOpenType( token, parentNode); propertyNode.ShouldBeSingleValueOpenPropertyAccessQueryNode(OpenPropertyName); }
/// <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 bool Visit(EndPathToken tokenIn) { if (isTableQuery) { stringBuilder.Append(tableEntityDotId); } else { stringBuilder.Append(EntityTranslator.GetPropertyName(tokenIn.Identifier, enableTimestampQuery)); } return(true); }
/// <summary> /// Write the property access token as URI part to this builder. /// </summary> /// <param name="endPath">To write as URI part.</param> private void WritePropertyAccess(EndPathToken endPath) { ExceptionUtils.CheckArgumentNotNull(endPath, "endPath"); if (endPath.NextToken != null) { this.WriteQuery(endPath.NextToken); this.builder.Append(ExpressionConstants.SymbolForwardSlash); } this.builder.Append(endPath.Identifier); }
public void ShouldThrowIfTypeNotOpen() { var token = new EndPathToken("Color", new RangeVariableToken("a")); EntityCollectionNode entityCollectionNode = new EntitySetNode(HardCodedTestModel.GetDogsSet()); SingleValueNode parentNode = new EntityRangeVariableReferenceNode("a", new EntityRangeVariable("a", HardCodedTestModel.GetPersonTypeReference(), entityCollectionNode)); Action getQueryNode = () => EndPathBinder.GeneratePropertyAccessQueryForOpenType( token, parentNode); getQueryNode.ShouldThrow <ODataException>().WithMessage( Strings.MetadataBinder_PropertyNotDeclared(parentNode.GetEdmTypeReference().FullName(), token.Identifier)); }
/// <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); } // Collection with any or all expression is already supported and handled separately. // Add support of collection with $count segment. CollectionNode colNode = parent as CollectionNode; if (colNode != null && endPathToken.Identifier.Equals(UriQueryConstants.CountSegment)) { // create a collection count node for collection node property. return(new CountNode(colNode)); } 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 static void VerifyAggregateExpressionToken(string expectedEndPathIdentifier, AggregationMethodDefinition expectedVerb, string expectedAlias, AggregateExpressionToken actual) { Assert.NotNull(actual.Expression); EndPathToken expression = actual.Expression as EndPathToken; Assert.NotNull(expression); Assert.Equal(expectedEndPathIdentifier, expression.Identifier); Assert.Equal(expectedVerb.MethodLabel, actual.MethodDefinition.MethodLabel); Assert.Equal(expectedVerb.MethodKind, actual.MethodDefinition.MethodKind); Assert.Equal(expectedAlias, actual.Alias); }
private static void VerifyAggregateExpressionToken(string expectedEndPathIdentifier, AggregationMethodDefinition expectedVerb, string expectedAlias, AggregateExpressionToken actual) { actual.Expression.Should().NotBeNull(); EndPathToken expression = actual.Expression as EndPathToken; expression.Should().NotBeNull(); expression.Identifier.Should().Be(expectedEndPathIdentifier); actual.MethodDefinition.MethodLabel.Should().Be(expectedVerb.MethodLabel); actual.MethodDefinition.MethodKind.Should().Be(expectedVerb.MethodKind); actual.Alias.Should().Be(expectedAlias); }
public void ShouldThrowNotImplementedIfTypeIsOpen() { const string OpenPropertyName = "Style"; var token = new EndPathToken(OpenPropertyName, new RangeVariableToken("a")); CollectionResourceNode entityCollectionNode = new EntitySetNode(HardCodedTestModel.GetPaintingsSet()); SingleValueNode parentNode = new ResourceRangeVariableReferenceNode("a", new ResourceRangeVariable("a", HardCodedTestModel.GetPaintingTypeReference(), entityCollectionNode)); var state = new BindingState(this.configuration); var metadataBinder = new MetadataBinder(state); var endPathBinder = new EndPathBinder(metadataBinder.Bind, state); var propertyNode = endPathBinder.GeneratePropertyAccessQueryForOpenType( token, parentNode); propertyNode.ShouldBeSingleValueOpenPropertyAccessQueryNode(OpenPropertyName); }
private static void VerifyBinaryOperatorToken <T>(string expectedEndPathIdentifier, BinaryOperatorKind expectedOperator, T expectedLiteralValue, BinaryOperatorToken actual) { Assert.NotNull(actual); Assert.Equal(actual.OperatorKind, expectedOperator); EndPathToken left = actual.Left as EndPathToken; Assert.NotNull(left); Assert.Equal(left.Identifier, expectedEndPathIdentifier); LiteralToken right = actual.Right as LiteralToken; Assert.NotNull(right); Assert.Equal(right.Value, expectedLiteralValue); }
/// <summary> /// Determines the parent node. If the token has a parent, that token is bound. If not, then we /// use the implicit parameter from the BindingState as the parent node. /// </summary> /// <param name="segmentToken">Token to determine the parent node for.</param> /// <returns>A SingleValueQueryNode that is the parent node of the <paramref name="segmentToken"/>.</returns> private QueryNode DetermineParentNode(EndPathToken segmentToken) { ExceptionUtils.CheckArgumentNotNull(segmentToken, "segmentToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); if (segmentToken.NextToken != null) { return(this.bindMethod(segmentToken.NextToken)); } else { RangeVariable implicitRangeVariable = state.ImplicitRangeVariable; return(NodeFactory.CreateRangeVariableReferenceNode(implicitRangeVariable)); } }
private static void VerifyBinaryOperatorToken <T>(string expectedEndPathIdentifier, BinaryOperatorKind expectedOperator, T expectedLiteralValue, BinaryOperatorToken actual) { actual.Should().NotBeNull(); actual.OperatorKind.Should().Be(expectedOperator); EndPathToken left = actual.Left as EndPathToken; left.Should().NotBeNull(); left.Identifier.Should().Be(expectedEndPathIdentifier); LiteralToken right = actual.Right as LiteralToken; right.Should().NotBeNull(); right.Value.Should().Be(expectedLiteralValue); }
public void ShouldThrowIfTypeNotOpen() { var token = new EndPathToken("Color", new RangeVariableToken("a")); CollectionResourceNode entityCollectionNode = new EntitySetNode(HardCodedTestModel.GetDogsSet()); SingleValueNode parentNode = new ResourceRangeVariableReferenceNode("a", new ResourceRangeVariable("a", HardCodedTestModel.GetPersonTypeReference(), entityCollectionNode)); var state = new BindingState(this.configuration); var metadataBinder = new MetadataBinder(state); var endPathBinder = new EndPathBinder(metadataBinder.Bind, state); Action getQueryNode = () => endPathBinder.GeneratePropertyAccessQueryForOpenType( token, parentNode); getQueryNode.Throws <ODataException>( Strings.MetadataBinder_PropertyNotDeclared(parentNode.GetEdmTypeReference().FullName(), token.Identifier)); }
public Expression Visit(EndPathToken tokenIn) { if (tokenIn.Identifier.Equals("null", StringComparison.OrdinalIgnoreCase)) { return(Expression.Constant(null)); } var prop = _properties.FirstOrDefault(i => i.Name.Equals(tokenIn.Identifier, StringComparison.OrdinalIgnoreCase)); if (prop != null) { return(Expression.Property(_parameter, prop)); } return(Expression.Constant(tokenIn.Identifier)); }
public void ShouldNotThrowIfTypeNotOpenButAggregateApplied() { var token = new EndPathToken("Color", new RangeVariableToken("a")); CollectionResourceNode entityCollectionNode = new EntitySetNode(HardCodedTestModel.GetDogsSet()); SingleValueNode parentNode = new ResourceRangeVariableReferenceNode("a", new ResourceRangeVariable("a", HardCodedTestModel.GetPersonTypeReference(), entityCollectionNode)); var state = new BindingState(this.configuration); state.AggregatedPropertyNames = new HashSet <EndPathToken> { new EndPathToken("Color", new RangeVariableToken("a")) }; var metadataBinder = new MetadataBinder(state); var endPathBinder = new EndPathBinder(metadataBinder.Bind, state); var propertyNode = endPathBinder.GeneratePropertyAccessQueryForOpenType( token, parentNode); propertyNode.ShouldBeSingleValueOpenPropertyAccessQueryNode("Color"); }
private IEnumerable <EndPathToken> GetGroupByPaths(IEnumerable <GroupByPropertyNode> nodes, EndPathToken token) { foreach (var node in nodes) { var nodeToken = new EndPathToken(node.Name, token); if (node.ChildTransformations == null || !node.ChildTransformations.Any()) { yield return(nodeToken); } else { foreach (var child in GetGroupByPaths(node.ChildTransformations, nodeToken)) { yield return(child); } } } }
/// <summary> /// Binds a an end path token into a PropertyAccessToken, OpenPropertyToken, or FunctionCallToken. /// </summary> /// <param name="endPathToken">The property access token to bind.</param> /// <param name="state">State of the binding algorithm.</param> /// <returns>A Query node representing this endpath token, bound to metadata.</returns> internal QueryNode BindEndPath(EndPathToken endPathToken, BindingState state) { DebugUtils.CheckNoExternalCallers(); 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, state); 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 : structuredParentType.FindProperty(endPathToken.Identifier); if (property != null) { return(GeneratePropertyAccessQueryNode(singleValueParent, property)); } if (functionCallBinder.TryBindEndPathAsFunctionCall(endPathToken, singleValueParent, state, out boundFunction)) { return(boundFunction); } return(GeneratePropertyAccessQueryForOpenType(endPathToken, singleValueParent)); }
public void ManyParametersInScopeShouldNotInterfere() { var token = new EndPathToken("Shoe", null); EntityCollectionNode dogsEntityCollectionNode = new EntitySetNode(HardCodedTestModel.GetDogsSet()); EntityCollectionNode peopleEntityCollectionNode = new EntitySetNode(HardCodedTestModel.GetPeopleSet()); this.bindingState.RangeVariables.Push(new EntityRangeVariable("a", HardCodedTestModel.GetDogTypeReference(), dogsEntityCollectionNode)); this.bindingState.RangeVariables.Push(new EntityRangeVariable("b", HardCodedTestModel.GetDogTypeReference(), dogsEntityCollectionNode)); this.bindingState.RangeVariables.Push(new EntityRangeVariable("c", HardCodedTestModel.GetDogTypeReference(), dogsEntityCollectionNode)); this.bindingState.RangeVariables.Push(new EntityRangeVariable("d", HardCodedTestModel.GetDogTypeReference(), dogsEntityCollectionNode)); this.bindingState.RangeVariables.Push(new EntityRangeVariable("e", HardCodedTestModel.GetDogTypeReference(), dogsEntityCollectionNode)); this.bindingState.RangeVariables.Push(new EntityRangeVariable("f", HardCodedTestModel.GetPersonTypeReference(), peopleEntityCollectionNode)); this.bindingState.RangeVariables.Push(new EntityRangeVariable("g", HardCodedTestModel.GetPersonTypeReference(), peopleEntityCollectionNode)); this.bindingState.RangeVariables.Push(new EntityRangeVariable("h", HardCodedTestModel.GetPersonTypeReference(), peopleEntityCollectionNode)); this.bindingState.RangeVariables.Push(new EntityRangeVariable("i", HardCodedTestModel.GetPersonTypeReference(), peopleEntityCollectionNode)); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPersonShoeProp()). And.Source.ShouldBeEntityRangeVariableReferenceNode(ExpressionConstants.It); }
/// <summary> /// Determines the parent node. If the token has a parent, that token is bound. If not, then we /// use the implicit parameter from the BindingState as the parent node. /// </summary> /// <param name="segmentToken">Token to determine the parent node for.</param> /// <returns>A SingleValueQueryNode that is the parent node of the <paramref name="segmentToken"/>.</returns> private QueryNode DetermineParentNode(EndPathToken segmentToken) { ExceptionUtils.CheckArgumentNotNull(segmentToken, "segmentToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); if (segmentToken.NextToken != null) { return this.bindMethod(segmentToken.NextToken); } else { RangeVariable implicitRangeVariable = state.ImplicitRangeVariable; return NodeFactory.CreateRangeVariableReferenceNode(implicitRangeVariable); } }
/// <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; } // Collection with any or all expression is already supported and handled separately. // Add support of collection with $count segment. CollectionNode colNode = parent as CollectionNode; if (colNode != null && endPathToken.Identifier.Equals(UriQueryConstants.CountSegment)) { // create a collection count node for collection node property. return new CountNode(colNode); } 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 static void VerifyPropertyAccessQueryTokensAreEqual(EndPathToken expected, EndPathToken actual, AssertionHandler assert) { assert.AreEqual(expected.Identifier, actual.Identifier, "The Name of the property access token doesn't match the expected one."); VerifyQueryTokensAreEqual(expected.NextToken, actual.NextToken, assert); }
public void KindIsInnerPath() { EndPathToken endPathToken = new EndPathToken("stuff", new LiteralToken(1)); endPathToken.Kind.Should().Be(QueryTokenKind.EndPath); }
/// <summary> /// Try to bind an end path token as a function call. Used for bound functions without parameters /// that parse as end path tokens syntactically /// </summary> /// <param name="endPathToken">the end path token to bind</param> /// <param name="parent">the parent node to this end path token.</param> /// <param name="state">the current state of the binding algorithm</param> /// <param name="boundFunction">a single value function call node representing the function call, if it exists</param> /// <returns>true if we found a function for this token, false otherwise.</returns> internal bool TryBindEndPathAsFunctionCall(EndPathToken endPathToken, QueryNode parent, BindingState state, out QueryNode boundFunction) { return this.TryBindIdentifier(endPathToken.Identifier, null, parent, state, out boundFunction); }
/// <summary> /// Binds a property access token. /// </summary> /// <param name="endPathToken">The property access token to bind.</param> /// <returns>The bound property access token.</returns> protected virtual QueryNode BindEndPath(EndPathToken endPathToken) { EndPathBinder endPathBinder = new EndPathBinder(this.Bind, this.BindingState); return endPathBinder.BindEndPath(endPathToken); }
public void ParentSetCorrectly() { EndPathToken endPathToken = new EndPathToken("stuff", new LiteralToken(1)); endPathToken.NextToken.ShouldBeLiteralQueryToken(1); }
public void NameSetCorrectly() { EndPathToken endPathToken = new EndPathToken("stuff", new LiteralToken(1)); endPathToken.Identifier.Should().Be("stuff"); }
public void ShouldThrowIfTypeNotOpen() { var token = new EndPathToken("Color", new RangeVariableToken("a")); EntityCollectionNode entityCollectionNode = new EntitySetNode(HardCodedTestModel.GetDogsSet()); SingleValueNode parentNode = new EntityRangeVariableReferenceNode("a", new EntityRangeVariable("a", HardCodedTestModel.GetPersonTypeReference(), entityCollectionNode)); Action getQueryNode = () => EndPathBinder.GeneratePropertyAccessQueryForOpenType( token, parentNode); getQueryNode.ShouldThrow<ODataException>().WithMessage( Strings.MetadataBinder_PropertyNotDeclared(parentNode.GetEdmTypeReference().ODataFullName(), token.Identifier)); }
private bool RunBindEndPathAsFunctionCall(string endPathIdentifier, out QueryNode functionCallNode) { var boundFunctionCallToken = new EndPathToken(endPathIdentifier, null); return this.functionCallBinder.TryBindEndPathAsFunctionCall(boundFunctionCallToken, new EntityRangeVariableReferenceNode( ExpressionConstants.It, (EntityRangeVariable) this.binder.BindingState.ImplicitRangeVariable), this.binder.BindingState, out functionCallNode); }
public void ShouldNotThrowIfTypeNotOpenButAggregateApplied() { var token = new EndPathToken("Color", new RangeVariableToken("a")); EntityCollectionNode entityCollectionNode = new EntitySetNode(HardCodedTestModel.GetDogsSet()); SingleValueNode parentNode = new EntityRangeVariableReferenceNode("a", new EntityRangeVariable("a", HardCodedTestModel.GetPersonTypeReference(), entityCollectionNode)); var state = new BindingState(this.configuration); state.AggregatedPropertyNames = new List<string> { "Color" }; var metadataBinder = new MetadataBinder(state); var endPathBinder = new EndPathBinder(metadataBinder.Bind, state); var propertyNode = endPathBinder.GeneratePropertyAccessQueryForOpenType( token, parentNode); propertyNode.ShouldBeSingleValueOpenPropertyAccessQueryNode("Color"); }
public void PropertyAccessOnDateWorks() { var token = new EndPathToken("MyDate", null); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPersonMyDateProp()); }
public static IEnumerable<ExpressionTestCase> PropertyAccessTestCases(string [] propertyNames) { foreach (var properties in propertyNames.Variations().Where(p => p.Length > 0)) { // Simple property access paths QueryToken pathToken = null; foreach (string propertyName in properties) { pathToken = new InnerPathToken(propertyName, pathToken, null); } InnerPathToken pathNav = (InnerPathToken)pathToken; pathToken = new EndPathToken(pathNav.Identifier, pathNav.NextToken); yield return new ExpressionTestCase() { Expression = string.Join("/", properties), ExpectedToken = pathToken }; } }
/// <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); }
public void PropertyAccessOnTimeOfDayCollectionWorks() { var token = new EndPathToken("MyTimeOfDays", null); var result = this.propertyBinder.BindEndPath(token); result.ShouldBeCollectionPropertyAccessQueryNode(HardCodedTestModel.GetPersonMyTimeOfDaysProp()); }