/// <summary> /// Constructor for binderbase. /// </summary> /// <param name="bindMethod">Method to use for binding the parent token, if needed.</param> /// <param name="state">State of the metadata binding.</param> protected BinderBase(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) { ExceptionUtils.CheckArgumentNotNull(bindMethod, "bindMethod"); ExceptionUtils.CheckArgumentNotNull(state, "state"); this.bindMethod = bindMethod; this.state = state; }
public void BindApplyWithAggregateAndFilterShouldReturnApplyClause() { var tokens = _parser.ParseApply("aggregate(StockQuantity with sum as TotalPrice)/filter(TotalPrice eq 100)"); var metadataBiner = new MetadataBinder(_bindingState); var binder = new ApplyBinder(metadataBiner.Bind, _bindingState); var actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(2); var transformations = actual.Transformations.ToList(); var filter = transformations[1] as FilterTransformationNode; filter.Should().NotBeNull(); filter.Kind.Should().Be(TransformationNodeKind.Filter); var filtareClause = filter.FilterClause; filtareClause.Expression.Should().NotBeNull(); var binaryOperation = filtareClause.Expression as BinaryOperatorNode; binaryOperation.Should().NotBeNull(); var propertyConvertNode = binaryOperation.Left as ConvertNode; propertyConvertNode.Should().NotBeNull(); var propertyAccess = propertyConvertNode.Source as SingleValueOpenPropertyAccessNode; propertyAccess.Should().NotBeNull(); propertyAccess.Name.Should().Be("TotalPrice"); }
public void BindOrderByShouldReturnAnOrderByNodeForEachToken() { var metadataBinder = new MetadataBinder(this.bindingState); this.orderbyBinder = new OrderByBinder(metadataBinder.Bind); var tokens = GetDummyOrderbyTokenList(7); var result = orderbyBinder.BindOrderBy(this.bindingState, tokens); result.ThenBy.ThenBy.ThenBy.ThenBy.ThenBy.ThenBy.ThenBy.Should().BeNull(); }
public void BindOrderByShouldOrderByInEasyToConsumeOrder() { var metadataBinder = new MetadataBinder(this.bindingState); this.orderbyBinder = new OrderByBinder(metadataBinder.Bind); var tokens = GetDummyOrderbyTokenList(2); // $orderby=prop0, prop1 var result = orderbyBinder.BindOrderBy(this.bindingState, tokens); result.Expression.ShouldBeConstantQueryNode("prop0"); result.ThenBy.Expression.ShouldBeConstantQueryNode("prop1"); }
internal static List<OperationSegmentParameter> BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection<FunctionParameterToken> segmentParameterTokens) { // TODO: HandleComplexOrCollectionParameterValueIfExists is temp work around for single copmlex or colleciton type, it can't handle nested complex or collection value. ICollection<FunctionParameterToken> parametersParsed = FunctionCallBinder.HandleComplexOrCollectionParameterValueIfExists(configuration.Model, functionOrOpertion, segmentParameterTokens, configuration.Resolver.EnableCaseInsensitive, configuration.EnableUriTemplateParsing); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = null; state.RangeVariables.Clear(); MetadataBinder binder = new MetadataBinder(state); List<OperationSegmentParameter> boundParameters = new List<OperationSegmentParameter>(); IDictionary<string, SingleValueNode> input = new Dictionary<string, SingleValueNode>(StringComparer.Ordinal); foreach (var paraToken in parametersParsed) { // TODO: considering another better exception if (paraToken.ValueToken is EndPathToken) { throw new ODataException(Strings.MetadataBinder_ParameterNotInScope( string.Format(CultureInfo.InvariantCulture, "{0}={1}", paraToken.ParameterName, (paraToken.ValueToken as EndPathToken).Identifier))); } SingleValueNode boundNode = (SingleValueNode)binder.Bind(paraToken.ValueToken); if (!input.ContainsKey(paraToken.ParameterName)) { input.Add(paraToken.ParameterName, boundNode); } } IDictionary<IEdmOperationParameter, SingleValueNode> result = configuration.Resolver.ResolveOperationParameters(functionOrOpertion, input); foreach (var item in result) { SingleValueNode boundNode = item.Value; // ensure node type is compatible with parameter type. var sourceTypeReference = boundNode.GetEdmTypeReference(); bool sourceIsNullOrOpenType = (sourceTypeReference == null); if (!sourceIsNullOrOpenType) { // if the node has been rewritten, no further conversion is needed. if (!TryRewriteIntegralConstantNode(ref boundNode, item.Key.Type)) { boundNode = MetadataBindingUtils.ConvertToTypeIfNeeded(boundNode, item.Key.Type); } } OperationSegmentParameter boundParamer = new OperationSegmentParameter(item.Key.Name, boundNode); boundParameters.Add(boundParamer); } return boundParameters; }
/// <summary> /// Constructs a EnumBinder with the given method to be used binding the parent token if needed. /// </summary> /// <param name="bindMethod">Method to use for binding the parent token, if needed.</param> internal EnumBinder(MetadataBinder.QueryTokenVisitor bindMethod) { this.bindMethod = bindMethod; }
/// <summary> /// Constructs a InnerPathTokenBinder. /// </summary> /// <param name="bindMethod">Bind method to use for binding a parent node, if needed.</param> /// <param name="state">State of the metadata binding.</param> internal InnerPathTokenBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) : base(bindMethod, state) { }
/// <summary> /// Constructs a DottedIdentifierBinder with the given method to be used binding the parent token if needed. /// </summary> /// <param name="bindMethod">Method to use for binding the parent token, if needed.</param> /// <param name="state">State of the metadata binding.</param> internal DottedIdentifierBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) : base(bindMethod, state) { }
/// <summary> /// Parses an <paramref name="orderBy "/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided model. /// </summary> /// <param name="orderBy">String representation of the orderby expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the orderby clause refers to.</param> /// <param name="navigationSource">NavigationSource that the elements are from.</param> /// <returns>An <see cref="OrderByClause"/> representing the metadata bound orderby expression.</returns> private OrderByClause ParseOrderByImplementation(string orderBy, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(orderBy, "orderBy"); // Get the syntactic representation of the orderby expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.OrderByLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); var orderByQueryTokens = expressionParser.ParseOrderBy(orderBy); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); if (applyClause != null) { state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames(); } MetadataBinder binder = new MetadataBinder(state); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); OrderByClause orderByClause = orderByBinder.BindOrderBy(state, orderByQueryTokens); return orderByClause; }
/// <summary> /// Parses a <paramref name="filter"/> clause on the given <paramref name="elementType"/>, binding /// the text into semantic nodes using the provided model. /// </summary> /// <param name="filter">String representation of the filter expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the filter clause refers to.</param> /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param> /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns> private FilterClause ParseFilterImplementation(string filter, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(filter, "filter"); // Get the syntactic representation of the filter expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); QueryToken filterToken = expressionParser.ParseFilter(filter); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); if (applyClause != null) { state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames(); } MetadataBinder binder = new MetadataBinder(state); FilterBinder filterBinder = new FilterBinder(binder.Bind, state); FilterClause boundNode = filterBinder.BindFilter(filterToken); return boundNode; }
public void InnerPathTokenBinderShouldFailIfPropertySourceIsNotASingleValue() { var state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(HardCodedTestModel.GetDogTypeReference(), HardCodedTestModel.GetDogsSet()); var metadataBinder = new MetadataBinder(state); var binder = new InnerPathTokenBinder(metadataBinder.Bind, state); var token = new InnerPathToken("MyDog", new InnerPathToken("MyPeople", null, null), null); Action bind = () => binder.BindInnerPathSegment(token); bind.ShouldThrow<ODataException>().WithMessage(Strings.MetadataBinder_PropertyAccessSourceNotSingleValue("MyDog")); }
private void ResetState() { BindingState state = new BindingState(this.configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet()); state.RangeVariables.Push(state.ImplicitRangeVariable); binder = new MetadataBinder(state); this.functionCallBinder = new FunctionCallBinder(binder.Bind, state); }
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 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)); 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.ShouldThrow<ODataException>().WithMessage( Strings.MetadataBinder_PropertyNotDeclared(parentNode.GetEdmTypeReference().FullName(), token.Identifier)); }
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 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); }
/// <summary> /// Process the remaining query options (represent the set of custom query options after /// service operation parameters and system query options have been removed). /// </summary> /// <param name="bindingState">the current state of the binding algorithm.</param> /// <param name="bindMethod">pointer to a binder method.</param> /// <returns>The list of <see cref="QueryNode"/> instances after binding.</returns> public static List<QueryNode> ProcessQueryOptions(BindingState bindingState, MetadataBinder.QueryTokenVisitor bindMethod) { List<QueryNode> customQueryOptionNodes = new List<QueryNode>(); foreach (CustomQueryOptionToken queryToken in bindingState.QueryOptions) { QueryNode customQueryOptionNode = bindMethod(queryToken); if (customQueryOptionNode != null) { customQueryOptionNodes.Add(customQueryOptionNode); } } bindingState.QueryOptions = null; return customQueryOptionNodes; }
/// <summary> /// Creates a FilterBinder. /// </summary> /// <param name="bindMethod">Method to use to visit the token tree and bind the tokens recursively.</param> /// <param name="state">State to use for binding.</param> internal FilterBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) { this.bindMethod = bindMethod; this.state = state; }
public ApplyBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) { this.bindMethod = bindMethod; this.state = state; this.filterBinder = new FilterBinder(bindMethod, state); }
/// <summary> /// Constructs a FunctionCallBinder with the given method to be used binding the parent token if needed. /// </summary> /// <param name="bindMethod">Method to use for binding the parent token, if needed.</param> /// <param name="state">State of the metadata binding.</param> internal FunctionCallBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) : base(bindMethod, state) { }
public void KeyLookupOnNavPropIntegrationTest() { var state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(HardCodedTestModel.GetDogTypeReference(), HardCodedTestModel.GetDogsSet()); var metadataBinder = new MetadataBinder(state); var binder = new InnerPathTokenBinder(metadataBinder.Bind, state); var token = new InnerPathToken("MyPeople", null, new[] { new NamedValue(null, new LiteralToken(123)) }); var result = binder.BindInnerPathSegment(token); result.ShouldBeKeyLookupQueryNode(); }
public void BindApplyWitMultipleTokensShouldReturnApplyClause() { var tokens = _parser.ParseApply( "groupby((ID, SSN, LifeTime))/aggregate(LifeTime with sum as TotalLife)/groupby((TotalLife))/aggregate(TotalLife with sum as TotalTotalLife)"); var state = new BindingState(_configuration); var metadataBiner = new MetadataBinder(_bindingState); var binder = new ApplyBinder(metadataBiner.Bind, _bindingState); var actual = binder.BindApply(tokens); actual.Should().NotBeNull(); actual.Transformations.Should().HaveCount(4); var transformations = actual.Transformations.ToList(); var firstGroupBy = transformations[0] as GroupByTransformationNode; firstGroupBy.Should().NotBeNull(); var firstAggregate = transformations[1] as AggregateTransformationNode; firstAggregate.Should().NotBeNull(); var scecondGroupBy = transformations[2] as GroupByTransformationNode; scecondGroupBy.Should().NotBeNull(); var scecondAggregate = transformations[3] as AggregateTransformationNode; scecondAggregate.Should().NotBeNull(); }
/// <summary> /// Constructs a EndPathBinder object using the given function to bind parent token. /// </summary> /// <param name="bindMethod">Method to bind the EndPathToken's parent, if there is one.</param> /// <param name="state">State of the metadata binding.</param>am> /// <remarks> /// Make bindMethod of return type SingleValueQueryNode. /// </remarks> internal EndPathBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state) : base(bindMethod, state) { this.functionCallBinder = new FunctionCallBinder(bindMethod, state); }
/// <summary> /// Constructs a KeyBinder object using the given function to bind key values. /// </summary> /// <param name="keyValueBindMethod">Method to call to bind a value in a key.</param> internal KeyBinder(MetadataBinder.QueryTokenVisitor keyValueBindMethod) { this.keyValueBindMethod = keyValueBindMethod; }
/// <summary> /// Parses an <paramref name="apply"/> clause on the given <paramref name="elementType"/>, binding /// the text into a metadata-bound or dynamic properties to be applied using the provided model. /// </summary> /// <param name="apply">String representation of the apply expression.</param> /// <param name="configuration">The configuration used for binding.</param> /// <param name="elementType">Type that the apply clause refers to.</param> /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param> /// <returns>A <see cref="ApplyClause"/> representing the metadata bound apply expression.</returns> private static ApplyClause ParseApplyImplementation(string apply, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(elementType, "elementType"); ExceptionUtils.CheckArgumentNotNull(apply, "apply"); // Get the syntactic representation of the apply expression UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier); var applyTokens = expressionParser.ParseApply(apply); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource); state.RangeVariables.Push(state.ImplicitRangeVariable); MetadataBinder binder = new MetadataBinder(state); ApplyBinder applyBinder = new ApplyBinder(binder.Bind, state); ApplyClause boundNode = applyBinder.BindApply(applyTokens); return boundNode; }
/// <summary> /// Constructs a LambdaBinder. /// </summary> /// <param name="bindMethod">Method used to bind a parent token.</param> internal LambdaBinder(MetadataBinder.QueryTokenVisitor bindMethod) { ExceptionUtils.CheckArgumentNotNull(bindMethod, "bindMethod"); this.bindMethod = bindMethod; }
/// <summary> /// Parses the <paramref name="search"/> clause, binding /// the text into a metadata-bound list of properties to be selected using the provided model. /// </summary> /// <param name="search">String representation of the search expression from the URI.</param> /// <param name="configuration">The configuration used for binding.</param> /// <returns>A <see cref="SearchClause"/> representing the metadata bound search expression.</returns> private static SearchClause ParseSearchImplementation(string search, ODataUriParserConfiguration configuration) { ExceptionUtils.CheckArgumentNotNull(configuration, "configuration"); ExceptionUtils.CheckArgumentNotNull(search, "search"); SearchParser searchParser = new SearchParser(configuration.Settings.SearchLimit); QueryToken queryToken = searchParser.ParseSearch(search); // Bind it to metadata BindingState state = new BindingState(configuration); MetadataBinder binder = new MetadataBinder(state); SearchBinder searchBinder = new SearchBinder(binder.Bind); return searchBinder.BindSearch(queryToken); }
/// <summary> /// Generate an expand item (and a select item for the implicit nav prop if necessary) based on an ExpandTermToken /// </summary> /// <param name="tokenIn">the expandTerm token to visit</param> /// <returns>the expand item for this expand term token.</returns> private ExpandedNavigationSelectItem GenerateExpandItem(ExpandTermToken tokenIn) { ExceptionUtils.CheckArgumentNotNull(tokenIn, "tokenIn"); // ensure that we're always dealing with proper V4 syntax if (tokenIn.PathToNavProp.NextToken != null && !tokenIn.PathToNavProp.IsNamespaceOrContainerQualified()) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } PathSegmentToken currentToken = tokenIn.PathToNavProp; IEdmStructuredType currentLevelEntityType = this.EdmType; List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); PathSegmentToken firstNonTypeToken = currentToken; if (currentToken.IsNamespaceOrContainerQualified()) { pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(currentToken, this.Model, this.Settings.SelectExpandLimit, this.configuration.Resolver, ref currentLevelEntityType, out firstNonTypeToken)); } IEdmProperty edmProperty = this.configuration.Resolver.ResolveProperty(currentLevelEntityType, firstNonTypeToken.Identifier); if (edmProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(currentLevelEntityType.ODataFullName(), currentToken.Identifier)); } IEdmNavigationProperty currentNavProp = edmProperty as IEdmNavigationProperty; if (currentNavProp == null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_PropertyIsNotANavigationProperty(currentToken.Identifier, currentLevelEntityType.ODataFullName())); } if (firstNonTypeToken.NextToken != null) { // lastly... make sure that, since we're on a NavProp, that the next token isn't null. throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } pathSoFar.Add(new NavigationPropertySegment(currentNavProp, /*entitySet*/ null)); ODataExpandPath pathToNavProp = new ODataExpandPath(pathSoFar); SelectExpandClause subSelectExpand; if (tokenIn.ExpandOption != null) { subSelectExpand = this.GenerateSubExpand(currentNavProp, tokenIn); } else { subSelectExpand = BuildDefaultSubExpand(); } subSelectExpand = this.DecorateExpandWithSelect(subSelectExpand, currentNavProp, tokenIn.SelectOption); IEdmNavigationSource targetNavigationSource = null; if (this.NavigationSource != null) { targetNavigationSource = this.NavigationSource.FindNavigationTarget(currentNavProp); } // call MetadataBinder to build the filter clause FilterClause filterOption = null; if (tokenIn.FilterOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); FilterBinder filterBinder = new FilterBinder(binder.Bind, binder.BindingState); filterOption = filterBinder.BindFilter(tokenIn.FilterOption); } // call MetadataBinder again to build the orderby clause OrderByClause orderbyOption = null; if (tokenIn.OrderByOptions != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); orderbyOption = orderByBinder.BindOrderBy(binder.BindingState, tokenIn.OrderByOptions); } LevelsClause levelsOption = this.ParseLevels(tokenIn.LevelsOption, currentLevelEntityType, currentNavProp); SearchClause searchOption = null; if (tokenIn.SearchOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); SearchBinder searchBinder = new SearchBinder(binder.Bind); searchOption = searchBinder.BindSearch(tokenIn.SearchOption); } return(new ExpandedNavigationSelectItem(pathToNavProp, targetNavigationSource, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, levelsOption, searchOption, subSelectExpand)); }