/// <summary> /// Initializes a new instance of the <see cref="ODataQueryOptions"/> class based on the incoming request and some metadata information from /// the <see cref="ODataQueryContext"/>. /// </summary> /// <param name="context">The <see cref="ODataQueryContext"/> which contains the <see cref="IEdmModel"/> and some type information</param> /// <param name="request">The incoming request message</param> public ODataQueryOptions(ODataQueryContext context, HttpRequestMessage request) { if (context == null) { throw Error.ArgumentNull("context"); } if (request == null) { throw Error.ArgumentNull("request"); } // remember the context Context = context; // Parse the query from request Uri RawValues = new ODataRawQueryOptions(); IEnumerable<KeyValuePair<string, string>> queryParameters = request.GetQueryNameValuePairs(); foreach (KeyValuePair<string, string> kvp in queryParameters) { switch (kvp.Key) { case "$filter": RawValues.Filter = kvp.Value; ThrowIfEmpty(kvp.Value, "$filter"); Filter = new FilterQueryOption(kvp.Value, context); break; case "$orderby": RawValues.OrderBy = kvp.Value; ThrowIfEmpty(kvp.Value, "$orderby"); OrderBy = new OrderByQueryOption(kvp.Value, context); break; case "$top": RawValues.Top = kvp.Value; ThrowIfEmpty(kvp.Value, "$top"); Top = new TopQueryOption(kvp.Value, context); break; case "$skip": RawValues.Skip = kvp.Value; ThrowIfEmpty(kvp.Value, "$skip"); Skip = new SkipQueryOption(kvp.Value, context); break; case "$select": RawValues.Select = kvp.Value; break; case "$inlinecount": RawValues.InlineCount = kvp.Value; break; case "$expand": RawValues.Expand = kvp.Value; break; case "$skiptoken": RawValues.SkipToken = kvp.Value; break; default: // we don't throw if we can't recognize the query break; } } }
public void Value_Returns_ParsedTopValue(string topValue, int expectedValue) { var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel(); var context = new ODataQueryContext(model, typeof(Customer)); var top = new TopQueryOption(topValue, context); Assert.Equal(expectedValue, top.Value); }
public void ApplyInvalidSkipQueryThrows(string topValue) { var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel(); var context = new ODataQueryContext(model, typeof(Customer)); var top = new TopQueryOption(topValue, context); Assert.Throws<ODataException>(() => top.ApplyTo(ODataQueryOptionTest.Customers, new ODataQuerySettings())); }
private static IQuery Apply(this IQuery query, TopQueryOption topQuery) { if (topQuery != null) { query = query.SetMaxResults(topQuery.Value); } return query; }
public void CanConstructValidFilterQuery(string topValue) { var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel(); var context = new ODataQueryContext(model, typeof(Customer)); var top = new TopQueryOption(topValue, context); Assert.Same(context, top.Context); Assert.Equal(topValue, top.RawValue); }
public void ApplyTo_WithUnTypedContext_Throws_InvalidOperation() { // Arrange CustomersModelWithInheritance model = new CustomersModelWithInheritance(); ODataQueryContext context = new ODataQueryContext(model.Model, model.Customer); TopQueryOption top = new TopQueryOption("42", context); IQueryable queryable = new Mock<IQueryable>().Object; // Act & Assert Assert.Throws<NotSupportedException>(() => top.ApplyTo(queryable, new ODataQuerySettings()), "The query option is not bound to any CLR type. 'ApplyTo' is only supported with a query option bound to a CLR type."); }
public static HttpRequestMessage BuildCustomRequest(this ODataQueryOptions originalOptions, out TopQueryOption top, out SkipQueryOption skip, out OrderByQueryOption orderBy) { top = null; skip = null; orderBy = null; // cuttin out $top and $skip from the request HttpRequestMessage customRequest = originalOptions.Request; if (customRequest.Properties.ContainsKey(HttpPropertyKeys.RequestQueryNameValuePairsKey)) { Uri uri = originalOptions.Request.RequestUri; var pairs = customRequest.Properties[HttpPropertyKeys.RequestQueryNameValuePairsKey] as IEnumerable<KeyValuePair<string, string>>; if (pairs != null) { IEnumerable<KeyValuePair<string, string>> jQueryNameValuePairs = new FormDataCollection(uri).GetJQueryNameValuePairs(); var updatedPairs = new List<KeyValuePair<string, string>>(); foreach (var pair in jQueryNameValuePairs) { if (pair.Key.Equals("$top")) { top = originalOptions.Top; } else if (pair.Key.Equals("$skip")) { skip = originalOptions.Skip; } else if (pair.Key.Equals("$orderby")) { orderBy = originalOptions.OrderBy; } else { updatedPairs.Add(pair); } } customRequest.Properties.Remove(HttpPropertyKeys.RequestQueryNameValuePairsKey); customRequest.Properties.Add(HttpPropertyKeys.RequestQueryNameValuePairsKey, updatedPairs); } } return customRequest; }
public void CanApplyTop() { var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel(); var topOption = new TopQueryOption("1", new ODataQueryContext(model, typeof(Customer), "Customers")); var customers = (new List<Customer>{ new Customer { CustomerId = 1, Name = "Andy" }, new Customer { CustomerId = 2, Name = "Aaron" }, new Customer { CustomerId = 3, Name = "Alex" } }).AsQueryable(); var results = topOption.ApplyTo(customers).ToArray(); Assert.Equal(1, results.Length); Assert.Equal(1, results[0].CustomerId); }
/// <summary> /// Validates a <see cref="TopQueryOption" />. /// </summary> /// <param name="topQueryOption">The $top query.</param> /// <param name="validationSettings">The validation settings.</param> public virtual void Validate(TopQueryOption topQueryOption, ODataValidationSettings validationSettings) { if (topQueryOption == null) { throw Error.ArgumentNull("topQueryOption"); } if (validationSettings == null) { throw Error.ArgumentNull("validationSettings"); } if (topQueryOption.Value > validationSettings.MaxTop) { throw new ODataException(Error.Format(SRResources.SkipTopLimitExceeded, validationSettings.MaxTop, AllowedQueryOptions.Top, topQueryOption.Value)); } }
private string BuildSkipTopClause(TopQueryOption topQueryOption, SkipQueryOption skipQueryOption) { string skipTopClause = string.Empty; if (topQueryOption != null) { int skipValue = skipQueryOption?.Value ?? 0; skipTopClause = $"OFFSET {skipValue} ROWS FETCH NEXT {topQueryOption.Value} ROWS ONLY"; } if (topQueryOption == null && skipQueryOption != null) { skipTopClause = $"OFFSET {skipQueryOption.Value} ROWS"; } return(skipTopClause); }
public ODataQueryOptions(IEnumerable <KeyValuePair <string, string> > queryParameters, ODataQueryContext context, bool aggregate) { if (queryParameters == null) { throw new ArgumentNullException(nameof(queryParameters)); } foreach (var queryParameter in queryParameters) { switch (queryParameter.Key) { case "$filter": if (!aggregate) { Filter = new FilterQueryOption(queryParameter.Value, context); } break; case "$orderby": OrderBy = new OrderByQueryOption(queryParameter.Value, context); break; case "$select": if (aggregate) { Select = new SelectExpandQueryOption(queryParameter.Value, string.Empty, context); } break; case "$top": Top = new TopQueryOption(queryParameter.Value, context); break; case "$format": break; default: throw new ArgumentException($"'{queryParameter.Key}' option is not supported"); } } }
public void CanApplySkipTopOrderby() { var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel(); var context = new ODataQueryContext(model, typeof(Customer)) { RequestContainer = new MockContainer() }; var orderbyOption = new OrderByQueryOption("Name", context); var skipOption = new SkipQueryOption("2", context); var topOption = new TopQueryOption("2", context); var customers = (new List <Customer> { new Customer { CustomerId = 1, Name = "Andy" }, new Customer { CustomerId = 2, Name = "Aaron" }, new Customer { CustomerId = 3, Name = "Alex" }, new Customer { CustomerId = 4, Name = "Ace" }, new Customer { CustomerId = 5, Name = "Abner" } }).AsQueryable(); IQueryable queryable = orderbyOption.ApplyTo(customers); queryable = skipOption.ApplyTo(queryable, new ODataQuerySettings()); queryable = topOption.ApplyTo(queryable, new ODataQuerySettings()); var results = ((IQueryable <Customer>)queryable).ToArray(); Assert.Equal(2, results.Length); Assert.Equal(4, results[0].CustomerId); Assert.Equal(3, results[1].CustomerId); }
public void CanApplyTop() { var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel(); var topOption = new TopQueryOption("1", new ODataQueryContext(model, typeof(Customer))); var customers = (new List <Customer> { new Customer { CustomerId = 1, Name = "Andy" }, new Customer { CustomerId = 2, Name = "Aaron" }, new Customer { CustomerId = 3, Name = "Alex" } }).AsQueryable(); var results = topOption.ApplyTo(customers, new ODataQuerySettings()).ToArray(); Assert.Single(results); Assert.Equal(1, results[0].CustomerId); }
public void CanApplySkipTopOrderby() { var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel(); var context = new ODataQueryContext(model, typeof(Customer)); var orderbyOption = new OrderByQueryOption("Name", context, queryTranslator: null); var skipOption = new SkipQueryOption("2", context); var topOption = new TopQueryOption("2", context); var customers = (new List<Customer>{ new Customer { CustomerId = 1, Name = "Andy" }, new Customer { CustomerId = 2, Name = "Aaron" }, new Customer { CustomerId = 3, Name = "Alex" }, new Customer { CustomerId = 4, Name = "Ace" }, new Customer { CustomerId = 5, Name = "Abner" } }).AsQueryable(); IQueryable queryable = orderbyOption.ApplyTo(customers); queryable = skipOption.ApplyTo(queryable, new ODataQuerySettings()); queryable = topOption.ApplyTo(queryable, new ODataQuerySettings()); var results = ((IQueryable<Customer>)queryable).ToArray(); Assert.Equal(2, results.Length); Assert.Equal(4, results[0].CustomerId); Assert.Equal(3, results[1].CustomerId); }
public void Property_Value_WorksWithUnTypedContext() { // Arrange CustomersModelWithInheritance model = new CustomersModelWithInheritance(); ODataQueryContext context = new ODataQueryContext(model.Model, model.Customer); TopQueryOption top = new TopQueryOption("42", context); // Act & Assert Assert.Equal(42, top.Value); }
public static IAsyncEnumerable <T> ApplyTo <T>(this TopQueryOption query, IAsyncEnumerable <T> source, ODataQuerySettings settings) { return(source.TakeAsync(query.Value)); }
/// <summary> /// Updates the QueryExpression's paging settings based on OData parameters. /// </summary> /// <param name="pagingInfo">The target PagingInfo</param> /// <param name="skip">The OData options that describe how many records to skip.</param> /// <param name="top">The OData options that describe how many records per page.</param> private static void UpdatePagingFromSkipAndTop(PagingInfo pagingInfo, SkipQueryOption skip, TopQueryOption top) { if (top == null) { pagingInfo.Count = 50; } else { pagingInfo.Count = top.Value; } if (skip == null) { pagingInfo.PageNumber = 1; } else { // When syncing for offline, the client will always request a page immediately after // the last record. So if there are only 7 records, it will request with $top=50 and // $skip=7. To handle these cases when $skip is not evenly divisible by $top, we round // up, which will send back an empty result set on the last page and complete the sync. pagingInfo.PageNumber = (int)Math.Ceiling((double)skip.Value / pagingInfo.Count) + 1; } }
private string BuildOrderClause(EdmEntityType edmEntityType, OrderByQueryOption orderByQueryOption, TopQueryOption topQueryOption, SkipQueryOption skipQueryOption) { string orderClause = BuildOrderClause(edmEntityType, orderByQueryOption); string skipTopClause = BuildSkipTopClause(topQueryOption, skipQueryOption); if (string.IsNullOrEmpty(skipTopClause)) { return(orderClause); } return($"{orderClause} {skipTopClause}"); }
private static bool ValidateTopQueryOption(TopQueryOption top) { if (top != null && top.RawValue != null) { int topValue = Int32.Parse(top.RawValue, NumberStyles.None); return topValue < 10; } return true; }
private Task <IEnumerable <PackageName> > Query(FeedPrincipal principal, string packageNamePrefix, SkipQueryOption skip, TopQueryOption top) { var feed = storage.GetFeed(principal.FeedName); switch (principal.AuthenticatedArea) { case AuthenticatedArea.QueryingOwn: return(skip != null && top != null ? feed.QueryPackages(principal.Identity.Name, principal.PackageState, packageNamePrefix, skip.Value, top.Value) : feed.QueryPackages(principal.Identity.Name, principal.PackageState)); case AuthenticatedArea.QueryingAll: return(skip != null && top != null ? feed.QueryPackages(principal.PackageState, packageNamePrefix, skip.Value, top.Value) : feed.QueryPackages(principal.PackageState)); default: throw new ArgumentOutOfRangeException("area", principal.AuthenticatedArea, null); } }
public void Value_ThrowsODataException_ForInvalidValues(string skipValue) { var model = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetEdmModel(); var context = new ODataQueryContext(model, typeof(Customer)); var top = new TopQueryOption(skipValue, context); Assert.Throws<ODataException>(() => top.Value); }
public void CanTurnOffValidationForTop() { // Arrange ODataValidationSettings settings = new ODataValidationSettings() { MaxTop = 10 }; TopQueryOption option = new TopQueryOption("11", ValidationTestHelper.CreateCustomerContext()); // Act and Assert Assert.Throws<ODataException>(() => option.Validate(settings), "The limit of '10' for Top query has been exceeded. The value from the incoming request is '11'."); option.Validator = null; Assert.DoesNotThrow(() => option.Validate(settings)); }