/// <summary> /// Binds a <see cref="SyntacticTree"/>. /// </summary> /// <param name="syntax">The query descriptor token to bind.</param> /// <returns>The bound query descriptor.</returns> public ODataUri BindTree(SyntacticTree syntax) { ExceptionUtils.CheckArgumentNotNull(syntax, "syntax"); ExceptionUtils.CheckArgumentNotNull(syntax.Path, "syntax.Path"); // Make a copy of query options since we may consume some of them as we bind the query bindingState.QueryOptions = new List <CustomQueryOptionToken>(syntax.QueryOptions); ODataPath path = null; FilterClause filter = null; OrderByClause orderBy = null; long? skip = null; long? top = null; SelectExpandClause selectExpand = null; InlineCountKind? inlineCount = null; // First bind the path path = ODataPathFactory.BindPath(syntax.Path, this.bindingState.Configuration); // If the path leads to a collection, then create a range variable that represents iterating over the collection var rangeVariable = NodeFactory.CreateImplicitRangeVariable(path); if (rangeVariable != null) { this.bindingState.RangeVariables.Push(rangeVariable); } if (syntax.Filter != null || syntax.OrderByTokens.Any()) { this.bindingState.ImplicitRangeVariable = this.bindingState.RangeVariables.Peek(); } // Apply filter first, then order-by, skip, top, select and expand filter = BindFilter(syntax, rangeVariable); orderBy = BindOrderBy(syntax, rangeVariable, path); skip = BindSkip(syntax, rangeVariable, path); top = BindTop(syntax, rangeVariable, path); selectExpand = BindSelectExpand(syntax, path, this.bindingState.Configuration); inlineCount = BindInlineCount(syntax, path); // Add the remaining query options to the query descriptor. List <QueryNode> boundQueryOptions = MetadataBinder.ProcessQueryOptions(this.bindingState, this.bindMethod); Debug.Assert(bindingState.QueryOptions == null, "this.queryOptions == null"); bindingState.RangeVariables.Pop(); bindingState.ImplicitRangeVariable = null; return(new ODataUri(path, boundQueryOptions, selectExpand, filter, orderBy, skip, top, inlineCount)); }
/// <summary> /// Bind a select and expand option. /// </summary> /// <param name="syntax">A syntax tree containing the select and expand options to bind</param> /// <param name="path">the top level path</param> /// <param name="configuration">The configuration to use for binding.</param> /// <returns>a select expand clause bound to metadata</returns> public static SelectExpandClause BindSelectExpand(SyntacticTree syntax, ODataPath path, ODataUriParserConfiguration configuration) { if (syntax.Select != null || syntax.Expand != null) { if (!path.EdmType().IsEntityCollection() && !path.EdmType().IsEntity()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$select or $expand")); } return(SelectExpandSemanticBinder.Parse((IEdmEntityType)((IEdmCollectionTypeReference)path.EdmType()).ElementType().Definition, path.EntitySet(), syntax.Expand, syntax.Select, configuration)); } return(null); }
/// <summary> /// Bind a skip option /// </summary> /// <param name="syntax">a syntax tree containing the skip option</param> /// <param name="rangeVariable">the range variable that iterates over the top level collection</param> /// <param name="path">the top level path.</param> /// <returns>a nullable long representing this skip option</returns> public static long?BindSkip(SyntacticTree syntax, RangeVariable rangeVariable, ODataPath path) { if (syntax.Skip != null) { if (rangeVariable == null || !path.EdmType().IsEntityCollection()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$skip")); } return(MetadataBinder.ProcessSkip(syntax.Skip)); } return(null); }
/// <summary> /// Bind an inline count option /// </summary> /// <param name="syntax">The inline count option to bind.</param> /// <param name="path">the top level path</param> /// <returns>an InlineCountKind representing this inline count option</returns> public static InlineCountKind?BindInlineCount(SyntacticTree syntax, ODataPath path) { if (syntax.InlineCount != null) { if (!path.EdmType().IsEntityCollection()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$inlinecount")); } return(syntax.InlineCount.Value); } return(null); }
/// <summary> /// Bind a filter option /// </summary> /// <param name="syntax">a syntactic tree containing the filter option</param> /// <param name="rangeVariable">the range variable that iterates over the top level collection.</param> /// <returns>A filter clause representing this filter option</returns> public FilterClause BindFilter(SyntacticTree syntax, RangeVariable rangeVariable) { if (syntax.Filter != null) { if (rangeVariable == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$filter")); } FilterBinder filterBinder = new FilterBinder(this.bindMethod, this.bindingState); return(filterBinder.BindFilter(syntax.Filter)); } return(null); }
/// <summary> /// Bind an orderby option /// </summary> /// <param name="syntax">a syntac tree containing the orderby option</param> /// <param name="rangeVariable">the range variable that iterates over the top level collection</param> /// <param name="path">the top level path</param> /// <returns>an OrderByClause representing this orderby option</returns> public OrderByClause BindOrderBy(SyntacticTree syntax, RangeVariable rangeVariable, ODataPath path) { if (syntax.OrderByTokens != null && syntax.OrderByTokens.Any()) { if (rangeVariable == null || !path.EdmType().IsEntityCollection()) { throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$orderby")); } OrderByBinder orderByBinder = new OrderByBinder(this.bindMethod); return(orderByBinder.BindOrderBy(this.bindingState, syntax.OrderByTokens)); } return(null); }
/// <summary> /// Parses the full Uri. /// </summary> /// <param name="fullUri">The full uri to parse</param> /// <returns>An ODataUri representing the full uri</returns> private ODataUri ParseUriImplementation(Uri fullUri) { ExceptionUtils.CheckArgumentNotNull(this.configuration.Model, "model"); ExceptionUtils.CheckArgumentNotNull(this.configuration.ServiceRoot, "serviceRoot"); ExceptionUtils.CheckArgumentNotNull(fullUri, "fullUri"); SyntacticTree syntax = SyntacticTree.ParseUri(fullUri, this.configuration.ServiceRoot, this.Settings.FilterLimit); ExceptionUtils.CheckArgumentNotNull(syntax, "syntax"); BindingState state = new BindingState(this.configuration); MetadataBinder binder = new MetadataBinder(state); ODataUriSemanticBinder uriBinder = new ODataUriSemanticBinder(state, binder.Bind); return(uriBinder.BindTree(syntax)); }
/// <summary> /// Create a URI for the given queryDescriptor given the base service URI. /// </summary> /// <param name="baseUri">The base service URI.</param> /// <param name="queryDescriptor">The query descriptor to create the result URI from.</param> /// <returns>An absolute URI that base on the baseUri and represent the queryDescriptor.</returns> public static Uri CreateUri(Uri baseUri, SyntacticTree queryDescriptor) { ExceptionUtils.CheckArgumentNotNull(baseUri, "baseUri"); ExceptionUtils.CheckArgumentNotNull(queryDescriptor, "queryDescriptor"); ODataUriBuilder odataUriBuilder = new ODataUriBuilder(queryDescriptor); string uriPart = odataUriBuilder.Build(); if (uriPart.StartsWith(ExpressionConstants.SymbolQueryStart, StringComparison.Ordinal)) { UriBuilder uriBuilder = new UriBuilder(baseUri); uriBuilder.Query = uriPart; return(uriBuilder.Uri); } return(new Uri(baseUri, new Uri(uriPart, UriKind.RelativeOrAbsolute))); }
/// <summary> /// Create a new Uri builder for the given token. /// </summary> /// <param name="query">The token to write out as Uri.</param> private ODataUriBuilder(SyntacticTree query) { this.query = query; }
/// <summary> /// Write the descriptor token as URI part to this builder. /// </summary> /// <param name="queryDescriptor">To write as URI part.</param> public void WriteQueryDescriptor(SyntacticTree queryDescriptor) { ExceptionUtils.CheckArgumentNotNull(queryDescriptor, "queryDescriptor"); this.WritePath(queryDescriptor.Path); bool writeQueryPrefix = true; if (queryDescriptor.Filter != null) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.builder.Append(UriQueryConstants.FilterQueryOption); this.builder.Append(ExpressionConstants.SymbolEqual); this.WriteQuery(queryDescriptor.Filter); } if (queryDescriptor.Select != null && queryDescriptor.Select.Properties.Count() > 0) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.WriteSelect(queryDescriptor.Select); } if (queryDescriptor.Expand != null && queryDescriptor.Expand.ExpandTerms.Count() > 0) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.WriteExpand(queryDescriptor.Expand); } if (queryDescriptor.OrderByTokens.Count() > 0) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.builder.Append(UriQueryConstants.OrderByQueryOption); this.builder.Append(ExpressionConstants.SymbolEqual); this.WriteOrderBys(queryDescriptor.OrderByTokens); } foreach (CustomQueryOptionToken queryOption in queryDescriptor.QueryOptions) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.WriteQueryOption(queryOption); } if (queryDescriptor.Top != null) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.builder.Append(UriQueryConstants.TopQueryOption); this.builder.Append(ExpressionConstants.SymbolEqual); this.builder.Append(queryDescriptor.Top); } if (queryDescriptor.Skip != null) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.builder.Append(UriQueryConstants.SkipQueryOption); this.builder.Append(ExpressionConstants.SymbolEqual); this.builder.Append(queryDescriptor.Skip); } if (queryDescriptor.Format != null) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.builder.Append(UriQueryConstants.FormatQueryOption); this.builder.Append(ExpressionConstants.SymbolEqual); this.builder.Append(queryDescriptor.Format); } if (queryDescriptor.InlineCount.HasValue) { this.WriteQueryPrefixOrSeparator(writeQueryPrefix); writeQueryPrefix = false; this.builder.Append(UriQueryConstants.InlineCountQueryOption); this.builder.Append(ExpressionConstants.SymbolEqual); this.builder.Append(queryDescriptor.InlineCount.Value.ToText()); } }