/// <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));
 }
Esempio n. 3
0
        /// <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()
                       ));
        }
Esempio n. 4
0
        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)
                       ));
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
 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));
 }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        /// <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)));
        }
Esempio n. 10
0
        /// <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);
        }
Esempio n. 12
0
 public ListResponse(IListRequest request, IEnumerable <T> data)
 {
     this.Data        = data;
     this.Meta        = this.Meta ?? new ListResponseMeta();
     this.Meta.Fields = request.Fields;
 }
Esempio n. 13
0
        /// <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));
        }