public IPaginationTransformResult <T> ApplyPagination <T>(IQueryable <T> query, HttpRequestMessage request) { var hasPageNumberParam = false; var hasPageSizeParam = false; var pageNumber = 0; var pageSize = _maxPageSize ?? DefaultPageSize; foreach (var kvp in request.GetQueryNameValuePairs()) { if (kvp.Key == PageNumberQueryParam) { hasPageNumberParam = true; if (!int.TryParse(kvp.Value, out pageNumber)) { throw JsonApiException.CreateForParameterError("Invalid page number", "Page number must be a positive integer.", PageNumberQueryParam); } } else if (kvp.Key == PageSizeQueryParam) { hasPageSizeParam = true; if (!int.TryParse(kvp.Value, out pageSize)) { throw JsonApiException.CreateForParameterError("Invalid page size", "Page size must be a positive integer.", PageSizeQueryParam); } } } if (!hasPageNumberParam && !hasPageSizeParam) { return(new DefaultPaginationTransformResult <T> { PagedQuery = query, PaginationWasApplied = false }); } if ((hasPageNumberParam && !hasPageSizeParam)) { throw JsonApiException.CreateForParameterError("Page size missing", string.Format("In order for paging to work properly, if either {0} or {1} is set, both must be.", PageNumberQueryParam, PageSizeQueryParam), PageNumberQueryParam); } if (pageNumber < 0) { throw JsonApiException.CreateForParameterError("Page number out of bounds", "Page number must not be negative.", PageNumberQueryParam); } if (pageSize <= 0) { throw JsonApiException.CreateForParameterError("Page size out of bounds", "Page size must be greater than or equal to 1.", PageSizeQueryParam); } if (_maxPageSize != null && pageSize > _maxPageSize.Value) { pageSize = _maxPageSize.Value; } if (pageNumber > 0) { pageNumber -= 1; // pagination is 1 based in frontend but zero based in backend! } var skip = pageNumber * pageSize; return(new DefaultPaginationTransformResult <T> { PageNumber = pageNumber, PageSize = pageSize, PagedQuery = query.Skip(skip).Take(pageSize), PaginationWasApplied = true }); }
public IOrderedQueryable <T> Sort <T>(IQueryable <T> query, string[] sortExpressions) { if (sortExpressions == null || sortExpressions.Length == 0) { sortExpressions = new [] { "id" } } ; var selectors = new List <ISelector <T> >(); var usedProperties = new Dictionary <PropertyInfo, object>(); var registration = _resourceTypeRegistry.GetRegistrationForType(typeof(T)); foreach (var sortExpression in sortExpressions) { if (string.IsNullOrEmpty(sortExpression)) { throw JsonApiException.CreateForParameterError("Empty sort expression", "One of the sort expressions is empty.", "sort"); } bool ascending; string fieldName; if (sortExpression[0] == '-') { ascending = false; fieldName = sortExpression.Substring(1); } else { ascending = true; fieldName = sortExpression; } if (string.IsNullOrWhiteSpace(fieldName)) { throw JsonApiException.CreateForParameterError("Empty sort expression", "One of the sort expressions is empty.", "sort"); } var paramExpr = Expression.Parameter(typeof(T)); Expression sortValueExpression; if (fieldName == "id") { sortValueExpression = registration.GetSortByIdExpression(paramExpr); } else { var modelProperty = registration.GetFieldByName(fieldName); if (modelProperty == null) { throw JsonApiException.CreateForParameterError("Attribute not found", string.Format("The attribute \"{0}\" does not exist on type \"{1}\".", fieldName, registration.ResourceTypeName), "sort"); } var property = modelProperty.Property; if (usedProperties.ContainsKey(property)) { throw JsonApiException.CreateForParameterError("Attribute specified more than once", string.Format("The attribute \"{0}\" was specified more than once.", fieldName), "sort"); } usedProperties[property] = null; sortValueExpression = Expression.Property(paramExpr, property); } var selector = GetSelector <T>(paramExpr, sortValueExpression, !ascending); selectors.Add(selector); } var firstSelector = selectors.First(); IOrderedQueryable <T> workingQuery = firstSelector.ApplyInitially(query); return(selectors.Skip(1).Aggregate(workingQuery, (current, selector) => selector.ApplySubsequently(current))); }