/// <summary> /// Creates a list response with links for the given query result using the given selector to map produce the <see cref="ListResponse{TDomain}.Data"/> type. /// </summary> /// <typeparam name="TQueryType">The data type that will be returned in the <see cref="ListQueryResult{T}"/></typeparam> /// <typeparam name="TResponseType">The data type that will be used in the <see cref="ListResponse{T}"/></typeparam> /// <param name="queryResult"></param> /// <param name="request"></param> /// <param name="properties"></param> /// <param name="selector"></param> /// <param name="currentUri">The URI of the current request.</param> /// <returns></returns> public static ListResponse <TResponseType> ToListResponse <TQueryType, TResponseType>( this ListQueryResult <TQueryType> queryResult, IListRequest request, IDictionary <string, ListItemPropertyInfo> properties, Func <TQueryType, TResponseType> selector, System.Uri currentUri ) { var response = ToListResponse <TQueryType, TResponseType>(queryResult, request, properties, selector); response.Links = new ListResponseLinks() { Self = currentUri.AbsoluteUri }; if (response.Meta?.Next?.Offset >= 0) { response.Links.Next = CreateUri(request, currentUri, response.Meta.Next.Value.Offset).ToString(); } if (response.Meta?.Prev?.Offset >= 0) { response.Links.Prev = CreateUri(request, currentUri, response.Meta.Prev.Value.Offset).ToString(); } return(response); }
/// <summary> /// Creates a list response from the given query result. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="queryResult"></param> /// <param name="request"></param> /// <param name="properties"></param> /// <returns></returns> public static ListResponse <T> ToListResponse <T>( this ListQueryResult <T> queryResult, IListRequest request, IDictionary <string, ListItemPropertyInfo> properties) where T : new() { return(ToListResponse <T, T>(queryResult, request, properties, s => s)); }
/// <summary> /// Handles a list request using the given query execution method. /// </summary> /// <typeparam name="TDomain"></typeparam> /// <typeparam name="TValidation"></typeparam> /// <typeparam name="TInfrastructure"></typeparam> /// <param name="controller"></param> /// <param name="request"></param> /// <param name="executeQueryMethod"></param> /// <param name="map"></param> /// <returns></returns> public static async Task <ActionResult <ListResponse <TDomain> > > HandleListRequestAsync <TDomain, TValidation, TInfrastructure>( this ControllerBase controller, IListRequest request, Func <ListQueryDefinition, Task <ListQueryResult <TInfrastructure> > > executeQueryMethod, Func <TInfrastructure, TDomain> map ) where TDomain : new() { var validator = controller.HttpContext.RequestServices.GetRequiredService <IListRequestValidator>(); var domainProperties = validator.GetProperties(typeof(TDomain)); var validationResult = validator.Validate <TValidation>(request); if (!validationResult.IsValid) { foreach (var error in validationResult.Errors) { controller.ModelState.AddModelError(error.Field, error.Error); } return(controller.ValidationProblem(controller.ModelState)); } var queryResult = await executeQueryMethod(validationResult.ListQuery); return(queryResult.ToListResponse <TInfrastructure, TDomain>( request, domainProperties, map, controller.HttpContext.Request.GetUri() )); }
public Task <IListResponse <TData> > PostAsync <TData>(string url, IListRequest request) { IEnumerable <TData> dataSource = null; if (typeof(TData) == typeof(Person)) { dataSource = this.People.Cast <TData>(); } else { throw new NotSupportedException(); } var properties = PropertyHelper.GetProperties(typeof(TData)); var resultData = dataSource.Skip(request.Offset.Value).Take(request.Limit.Value); var queryResult = new Csg.ListQuery.ListQueryResult <TData>( resultData, resultData.Count(), dataSource.Count(), true, request.Limit, (request.Offset + resultData.Count()) < dataSource.Count() ? request.Offset + request.Limit : (int?)null, request.Offset > 0 ? Math.Max(request.Offset.Value - request.Limit.Value, 0) :(int?)null ); return(Task.FromResult <IListResponse <TData> >( Csg.ListQuery.AspNetCore.ListQueryResultExtensions.ToListResponse <TData, TData>(queryResult, request, properties, x => x) )); }
public BookApiTests() { var stubVolumesResource = Substitute.For <IVolumesResource>(); _listRequest = Substitute.For <IListRequest>(); stubVolumesResource.List(Arg.Any <string>()).Returns(_listRequest); _bookService = Substitute.For <IBookService>(); _bookApi = new BookApi(_bookService); _bookService.Volumes .Returns(stubVolumesResource); Mapper.Initialize(x => x.AddProfile(typeof(MappingUnitTestConfiguration))); _listRequest.Execute().Returns(new Volumes() { Items = new List <Volume>() { new Volume() { Id = Books[0].Id, VolumeInfo = Mapper.Map <Volume.VolumeInfoData>(Books[0]) }, new Volume() { Id = Books[1].Id, VolumeInfo = Mapper.Map <Volume.VolumeInfoData>(Books[1]) }, new Volume() { Id = Books[2].Id, VolumeInfo = Mapper.Map <Volume.VolumeInfoData>(Books[2]) }, } }); _booksController = new BooksController(_bookApi); }
public static Task <ActionResult <ListResponse <TDomain> > > HandleListRequestAsync <TDomain>( this ControllerBase controller, IListRequest request, Func <ListQueryDefinition, Task <ListQueryResult <TDomain> > > executeQueryMethod ) where TDomain : new() { return(HandleListRequestAsync <TDomain, TDomain, TDomain>(controller, request, executeQueryMethod, x => x)); }
public static IQueryable <T> Paginate <T>(this IQueryable <T> entities, IListRequest listRequest) { if (listRequest.PageSize.HasValue) { return(entities.Paginate(listRequest.PageSize, listRequest.PageNumber)); } return(entities); }
/// <summary> /// The items. /// </summary> /// <param name="request"> /// The request. /// </param> /// <returns> /// The <see cref="InputValidation"/>. /// </returns> public InputValidation Items(IListRequest request) { if (request.ItemsPerPage < 1) { Throw("Page must be bigger then 0"); } return(this); }
private static Uri CreateUri(IListRequest request, Uri currentUri, int offset) { var keyPairs = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(currentUri.Query) .Where(x => x.Key.ToLower() != "offset") .Append(new KeyValuePair <string, Microsoft.Extensions.Primitives.StringValues>(nameof(request.Offset).ToLower(), offset.ToString())); var queryString = Microsoft.AspNetCore.Http.QueryString.Create(keyPairs).ToString() .Replace("%5B", "[") .Replace("%5D", "]") .Replace("%3A", ":"); return(new Uri(string.Concat(currentUri.GetUriWithoutQueryString(), queryString))); }
/// <summary> /// Transforms a list request into a list query /// </summary> /// <param name="selectableProperties">A set of properties used to validate the given selections</param> /// <param name="filerableProperties">A set of properties used to validate the given filters</param> /// <param name="sortableProperties">A set of properties used to validate the given sorts</param> /// <exception cref="MissingFieldException">When a field is not valid</exception> /// <returns></returns> public virtual ListRequestValidationResult Validate( IListRequest request, IDictionary <string, ListItemPropertyInfo> selectableProperties, IDictionary <string, ListItemPropertyInfo> filerableProperties, IDictionary <string, ListItemPropertyInfo> sortableProperties ) { var queryDef = CreateQueryDefinition(); var errors = new List <ListRequestValidationError>(); if (request.Fields != null) { queryDef.Fields = request.Fields.Select(s => new { Raw = s, Exists = selectableProperties.TryGetValue(s, out ListItemPropertyInfo domainProp), Domain = domainProp }).Where(field =>
/// <summary> /// Creates a list response from the given query result using the given selector to map produce the <see cref="ListResponse{T}.Data"/> type. /// </summary> /// <typeparam name="TQueryType">The data type that will be returned in the <see cref="ListQueryResult{T}"/></typeparam> /// <typeparam name="TResponseType">The data type that will be used in the <see cref="ListResponse{T}"/></typeparam> /// <param name="queryResult"></param> /// <param name="request"></param> /// <param name="properties">The properties that will be provided in <see cref="ListResponse{T}.Meta"/> properties.</param> /// <param name="selector">A function that maps <typeparamref name="TQueryType"/> to <typeparamref name="TResponseType"/></param> /// <returns></returns> public static ListResponse <TResponseType> ToListResponse <TQueryType, TResponseType>( this ListQueryResult <TQueryType> queryResult, IListRequest request, IDictionary <string, ListItemPropertyInfo> properties, Func <TQueryType, TResponseType> selector) { properties = properties ?? throw new ArgumentNullException(nameof(properties)); IEnumerable <TResponseType> data = queryResult.Data.Select(selector); int?dataCount = queryResult.IsBuffered ? data.Count() : (int?)null; var response = new ListResponse <TResponseType>() { Meta = new ListResponseMeta() { TotalCount = queryResult.TotalCount } }; if (request.Fields != null) { response.Meta.Fields = properties.Select(s => s.Value.JsonName).Intersect(request.Fields, StringComparer.OrdinalIgnoreCase); } else { response.Meta.Fields = properties.Select(s => s.Value.JsonName); } if (dataCount.HasValue) { response.Meta.CurrentCount = dataCount; } response.Meta.Next = queryResult.NextOffset.HasValue ? new PageInfo(queryResult.NextOffset.Value) : (PageInfo?)null; response.Meta.Prev = queryResult.PreviousOffset.HasValue ? new PageInfo(queryResult.PreviousOffset.Value) : (PageInfo?)null; response.Data = data; return(response); }
public ListResponse(IListRequest request, IEnumerable <T> data) { this.Data = data; this.Meta = this.Meta ?? new ListResponseMeta(); this.Meta.Fields = request.Fields; }
/// <summary> /// Gets all data from a given source by making multiple API calls for each page until the server indicates there are no more pages. /// </summary> /// <typeparam name="TData"></typeparam> /// <param name="client">The client to use for making requests.</param> /// <param name="url">The filter endpoint to send the request to</param> /// <param name="request">The list request definition</param> /// <param name="delayBetweenRequests">The delay (in milliseconds) to wait between requests.</param> /// <param name="maxPagesToFetch">The maximum number of pages to fetch from the API.</param> /// <param name="onRequestComplete"></param> /// <returns></returns> public static async Task <AggregateListResponse <TData> > PostAllPagesAsync <TData>(this IPagedListSupport client, string url, IListRequest request, int delayBetweenRequests = 25, int?maxPagesToFetch = null, Action <IListResponse <TData> > onRequestComplete = null) { IEnumerable <TData> result = new List <TData>(); int pageCount = 0; int totalCount = 0; int?nextOffset = request.Offset; while (nextOffset != null && pageCount < (maxPagesToFetch ?? Int32.MaxValue)) { await Task.Delay(delayBetweenRequests).ConfigureAwait(false); request.Offset = nextOffset.Value; var responseObject = await client.PostAsync <TData>(url, request).ConfigureAwait(false); result = result.Concat(responseObject.Data); nextOffset = responseObject.Meta?.Next?.Offset; pageCount++; totalCount += responseObject.Meta?.CurrentCount ?? 0; onRequestComplete?.Invoke(responseObject); } return(new AggregateListResponse <TData>(result, totalCount, pageCount)); }
/// <summary> /// Transforms a list request into a repository query /// </summary> /// <typeparam name="TSelectableProperties">A type that defines the selections and sortable fields allowed.</typeparam> /// <typeparam name="TFilterableProperties">A type that defines the filters allowed.</typeparam> /// <typeparam name="TSortableProperties">A type that defines the filters allowed.</typeparam> /// <param name="validator"></param> /// <returns></returns> public static ListRequestValidationResult Validate <TSelectableProperties, TFilterableProperties, TSortableProperties>(this IListRequestValidator validator, IListRequest request, int?maxRecursionDepth = null) { var selectProperties = validator.GetProperties(typeof(TSelectableProperties), maxRecursionDepth: maxRecursionDepth); var filterProperties = validator.GetProperties(typeof(TFilterableProperties), maxRecursionDepth: maxRecursionDepth); var orderProperties = validator.GetProperties(typeof(TSortableProperties), maxRecursionDepth: maxRecursionDepth); return(validator.Validate(request, selectProperties, filterProperties, orderProperties)); }
/// <summary> /// Transforms a list request into a repository query /// </summary> /// <typeparam name="TFieldValidationModel">A type that defines the selections and sortable fields allowed.</typeparam> /// <typeparam name="TFilterValidationModel">A type that defines the filters allowed.</typeparam> /// <param name="validator"></param> /// <returns></returns> public static ListRequestValidationResult Validate <TFieldValidationModel, TFilterValidationModel>(this IListRequestValidator validator, IListRequest request, int?maxRecursionDepth = null) { var fieldProperties = validator.GetProperties(typeof(TFieldValidationModel), maxRecursionDepth: maxRecursionDepth); var filterPropreties = validator.GetProperties(typeof(TFilterValidationModel), maxRecursionDepth: maxRecursionDepth); return(validator.Validate(request, fieldProperties, filterPropreties, fieldProperties)); }
/// <summary> /// Transforms a list request into a repository query /// </summary> /// <typeparam name="TValidationModel">A type that defines the selections, filters, and sortable fields allowed.</typeparam> /// <param name="validator"></param> /// <returns></returns> public static ListRequestValidationResult Validate <TValidationModel>(this IListRequestValidator validator, IListRequest request, int?maxRecursionDepth = null) { var properties = validator.GetProperties(typeof(TValidationModel), maxRecursionDepth: maxRecursionDepth); return(validator.Validate(request, properties, properties, properties)); }