/// <summary> /// Parses the <paramref name="queryUri"/> and binds the query to the metadata provided /// then returns a new instance of <see cref="QueryDescriptorQueryNode"/> /// describing the query specified by the uri. /// </summary> /// <param name="queryUri">The absolute URI which holds the query to parse. This must be a path relative to the <paramref name="serviceBaseUri"/>.</param> /// <param name="serviceBaseUri">The base URI of the service.</param> /// <param name="metadataProvider">The metadata provider to use for binding.</param> /// <param name="maxDepth">The maximum depth of any single query part. Security setting to guard against DoS attacks causing stack overflows and such.</param> /// <returns>A new instance of <see cref="QueryDescriptorQueryNode"/> which represents the query specified in the <paramref name="queryUri"/>.</returns> public static QueryDescriptorQueryNode ParseUri(Uri queryUri, Uri serviceBaseUri, IDataServiceMetadataProvider metadataProvider, int maxDepth) { ExceptionUtils.CheckArgumentNotNull(metadataProvider, "metadataProvider"); QueryDescriptorQueryToken queryDescriptorQueryToken = QueryDescriptorQueryToken.ParseUri(queryUri, serviceBaseUri, maxDepth); MetadataBinder metadataBinder = new MetadataBinder(metadataProvider); return(metadataBinder.BindQuery(queryDescriptorQueryToken)); }
public void TestParseTypeSetAccess() { var parseTree = QueryDescriptorQueryToken.ParseUri(new Uri("http://example.org/odata/Films"), new Uri("http://example.org/odata/")); Assert.IsNotNull(parseTree); Assert.AreEqual(QueryTokenKind.Segment, parseTree.Path.Kind); var segment = parseTree.Path as SegmentQueryToken; Assert.AreEqual("Films", segment.Name); Assert.IsNull(segment.NamedValues); }
/// <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, QueryDescriptorQueryToken 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 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, QueryDescriptorQueryToken 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))); }
public void TestParseInstanceAccess() { var parseTree = QueryDescriptorQueryToken.ParseUri( new Uri("http://example.org/odata/Films('Un_Chien_Andalou')"), new Uri("http://example.org/odata/")); Assert.IsNotNull(parseTree); Assert.IsNotNull(parseTree.Path); Assert.AreEqual(QueryTokenKind.Segment, parseTree.Path.Kind); Assert.IsInstanceOfType(parseTree.Path, typeof(SegmentQueryToken)); var sqt = parseTree.Path as SegmentQueryToken; Assert.AreEqual("Films", sqt.Name); Assert.IsNotNull(sqt.NamedValues); var namedValues = sqt.NamedValues.ToList(); Assert.AreEqual(1, namedValues.Count); Assert.IsNull(namedValues[0].Name); Assert.IsNotNull(namedValues[0].Value); Assert.IsNotNull(namedValues[0].Value.Value); Assert.AreEqual(QueryTokenKind.Literal, namedValues[0].Value.Kind); Assert.AreEqual("Un_Chien_Andalou", namedValues[0].Value.Value); }
/// <summary> /// Binds the specified <paramref name="queryDescriptorQueryToken"/> to the metadata and returns a bound query. /// </summary> /// <param name="queryDescriptorQueryToken">The lexical query descriptor for the query to process.</param> /// <returns>Metadata bound semantic query descriptor for the query.</returns> public QueryDescriptorQueryNode BindQuery(QueryDescriptorQueryToken queryDescriptorQueryToken) { ExceptionUtils.CheckArgumentNotNull(queryDescriptorQueryToken, "queryDescriptorQueryToken"); return this.BindQueryDescriptor(queryDescriptorQueryToken); }
/// <summary> /// Binds a <see cref="QueryDescriptorQueryToken"/>. /// </summary> /// <param name="queryDescriptorToken">The query descriptor token to bind.</param> /// <returns>The bound query descriptor.</returns> protected virtual QueryDescriptorQueryNode BindQueryDescriptor(QueryDescriptorQueryToken queryDescriptorToken) { ExceptionUtils.CheckArgumentNotNull(queryDescriptorToken, "queryDescriptorToken"); ExceptionUtils.CheckArgumentNotNull(queryDescriptorToken.Path, "queryDescriptorToken.Path"); // Make a copy of query options since we may consume some of them as we bind the query this.queryOptions = new List<QueryOptionQueryToken>(queryDescriptorToken.QueryOptions); //// TODO: check whether there is a $count segment at the top; if so strip it and first process everything else and //// then add it to the bound query tree at the end // First bind the path QueryNode query = this.Bind(queryDescriptorToken.Path); // Apply filter first, then order-by, skip, top, select and expand query = this.ProcessFilter(query, queryDescriptorToken.Filter); query = this.ProcessOrderBy(query, queryDescriptorToken.OrderByTokens); query = ProcessSkip(query, queryDescriptorToken.Skip); query = ProcessTop(query, queryDescriptorToken.Top); //// TODO: if we found a $count segment process it now and add it to the query QueryDescriptorQueryNode queryDescriptorNode = new QueryDescriptorQueryNode(); queryDescriptorNode.Query = query; // Add the remaining query options to the query descriptor. List<QueryNode> boundQueryOptions = this.ProcessQueryOptions(); queryDescriptorNode.CustomQueryOptions = new ReadOnlyCollection<QueryNode>(boundQueryOptions); Debug.Assert(this.queryOptions == null, "this.queryOptions == null"); return queryDescriptorNode; }
/// <summary> /// Create a new Uri builder for the given token. /// </summary> /// <param name="queryToken">The token to write out as Uri.</param> protected ODataUriBuilder(QueryDescriptorQueryToken queryToken) { this.queryToken = queryToken; }
/// <summary> /// Write the descriptor token as URI part to this builder. /// </summary> /// <param name="queryDescriptor">To write as URI part.</param> public virtual void WriteQueryDescriptor(QueryDescriptorQueryToken queryDescriptor) { ExceptionUtils.CheckArgumentNotNull(queryDescriptor, "queryDescriptor"); this.WriteQuery(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.Properties.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 (QueryOptionQueryToken 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()); } }
/// <summary> /// Parses the <paramref name="queryUri"/> and returns a new instance of <see cref="QueryDescriptorQueryToken"/> /// describing the query specified by the uri. /// </summary> /// <param name="queryUri">The absolute URI which holds the query to parse. This must be a path relative to the <paramref name="serviceBaseUri"/>.</param> /// <param name="serviceBaseUri">The base URI of the service.</param> /// <param name="maxDepth">The maximum depth of any single query part. Security setting to guard against DoS attacks causing stack overflows and such.</param> /// <returns>A new instance of <see cref="QueryDescriptorQueryToken"/> which represents the query specified in the <paramref name="queryUri"/>.</returns> public static QueryDescriptorQueryToken ParseUri(Uri queryUri, Uri serviceBaseUri, int maxDepth) { ExceptionUtils.CheckArgumentNotNull(queryUri, "queryUri"); if (!queryUri.IsAbsoluteUri) { throw new ArgumentException(Strings.QueryDescriptorQueryToken_UriMustBeAbsolute(queryUri), "queryUri"); } ExceptionUtils.CheckArgumentNotNull(serviceBaseUri, "serviceBaseUri"); if (!serviceBaseUri.IsAbsoluteUri) { throw new ArgumentException(Strings.QueryDescriptorQueryToken_UriMustBeAbsolute(serviceBaseUri), "serviceBaseUri"); } if (maxDepth <= 0) { throw new ArgumentException(Strings.QueryDescriptorQueryToken_MaxDepthInvalid, "maxDepth"); } QueryDescriptorQueryToken queryDescriptor = new QueryDescriptorQueryToken(); UriQueryPathParser pathParser = new UriQueryPathParser(maxDepth); queryDescriptor.Path = pathParser.ParseUri(queryUri, serviceBaseUri); List <QueryOptionQueryToken> queryOptions = HttpUtils.ParseQueryOptions(queryUri); string filter = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.FilterQueryOption); if (filter != null) { UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(maxDepth); queryDescriptor.Filter = expressionParser.ParseFilter(filter); } string orderBy = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.OrderByQueryOption); if (orderBy != null) { UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(maxDepth); queryDescriptor.OrderByTokens = expressionParser.ParseOrderBy(orderBy); } string skip = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.SkipQueryOption); if (skip != null) { int skipValue; if (!UriPrimitiveTypeParser.TryUriStringToNonNegativeInteger(skip, out skipValue)) { throw new ODataException(Strings.QueryDescriptorQueryToken_InvalidSkipQueryOptionValue(skip)); } queryDescriptor.Skip = skipValue; } string top = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.TopQueryOption); if (top != null) { int topValue; if (!UriPrimitiveTypeParser.TryUriStringToNonNegativeInteger(top, out topValue)) { throw new ODataException(Strings.QueryDescriptorQueryToken_InvalidTopQueryOptionValue(top)); } queryDescriptor.Top = topValue; } // the remaining query options are stored on the query descriptor queryDescriptor.QueryOptions = queryOptions.Count == 0 ? null : new ReadOnlyCollection <QueryOptionQueryToken>(queryOptions); return(queryDescriptor); }
/// <summary> /// Create a new Uri builder for the given token. /// </summary> /// <param name="queryToken">The token to write out as Uri.</param> protected ODataUriBuilder(QueryDescriptorQueryToken queryToken) { this.queryToken = queryToken; }
/// <summary> /// Write the descriptor token as URI part to this builder. /// </summary> /// <param name="queryDescriptor">To write as URI part.</param> public virtual void WriteQueryDescriptor(QueryDescriptorQueryToken queryDescriptor) { ExceptionUtils.CheckArgumentNotNull(queryDescriptor, "queryDescriptor"); this.WriteQuery(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.Properties.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 (QueryOptionQueryToken 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()); } }
/// <summary> /// Parses the <paramref name="queryUri"/> and returns a new instance of <see cref="QueryDescriptorQueryToken"/> /// describing the query specified by the uri. /// </summary> /// <param name="queryUri">The absolute URI which holds the query to parse. This must be a path relative to the <paramref name="serviceBaseUri"/>.</param> /// <param name="serviceBaseUri">The base URI of the service.</param> /// <param name="maxDepth">The maximum depth of any single query part. Security setting to guard against DoS attacks causing stack overflows and such.</param> /// <returns>A new instance of <see cref="QueryDescriptorQueryToken"/> which represents the query specified in the <paramref name="queryUri"/>.</returns> public static QueryDescriptorQueryToken ParseUri(Uri queryUri, Uri serviceBaseUri, int maxDepth) { ExceptionUtils.CheckArgumentNotNull(queryUri, "queryUri"); if (!queryUri.IsAbsoluteUri) { throw new ArgumentException(Strings.QueryDescriptorQueryToken_UriMustBeAbsolute(queryUri), "queryUri"); } ExceptionUtils.CheckArgumentNotNull(serviceBaseUri, "serviceBaseUri"); if (!serviceBaseUri.IsAbsoluteUri) { throw new ArgumentException(Strings.QueryDescriptorQueryToken_UriMustBeAbsolute(serviceBaseUri), "serviceBaseUri"); } if (maxDepth <= 0) { throw new ArgumentException(Strings.QueryDescriptorQueryToken_MaxDepthInvalid, "maxDepth"); } QueryDescriptorQueryToken queryDescriptor = new QueryDescriptorQueryToken(); UriQueryPathParser pathParser = new UriQueryPathParser(maxDepth); queryDescriptor.Path = pathParser.ParseUri(queryUri, serviceBaseUri); List<QueryOptionQueryToken> queryOptions = HttpUtils.ParseQueryOptions(queryUri); string filter = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.FilterQueryOption); if (filter != null) { UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(maxDepth); queryDescriptor.Filter = expressionParser.ParseFilter(filter); } string orderBy = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.OrderByQueryOption); if (orderBy != null) { UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(maxDepth); queryDescriptor.OrderByTokens = expressionParser.ParseOrderBy(orderBy); } string skip = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.SkipQueryOption); if (skip != null) { int skipValue; if (!UriPrimitiveTypeParser.TryUriStringToNonNegativeInteger(skip, out skipValue)) { throw new ODataException(Strings.QueryDescriptorQueryToken_InvalidSkipQueryOptionValue(skip)); } queryDescriptor.Skip = skipValue; } string top = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.TopQueryOption); if (top != null) { int topValue; if (!UriPrimitiveTypeParser.TryUriStringToNonNegativeInteger(top, out topValue)) { throw new ODataException(Strings.QueryDescriptorQueryToken_InvalidTopQueryOptionValue(top)); } queryDescriptor.Top = topValue; } // the remaining query options are stored on the query descriptor queryDescriptor.QueryOptions = queryOptions.Count == 0 ? null : new ReadOnlyCollection<QueryOptionQueryToken>(queryOptions); return queryDescriptor; }