Exemplo n.º 1
0
        /// <summary>
        /// Returns a new collection of DTOs with only the fields specified by the IListParameters having values.
        /// </summary>
        /// <param name="mappedResult">The items to be trimmed.</param>
        /// <param name="parameters">The parameters by which to trim.</param>
        /// <returns>The trimmed collection of DTOs.</returns>
        public virtual IList <TDto> TrimListFields <TDto>(IList <TDto> mappedResult, IListParameters parameters)
            where TDto : IClassDto <T>, new()
        {
            if (parameters.Fields.Any())
            {
                var allDtoProps    = typeof(TDto).GetProperties();
                var requestedProps = parameters.Fields
                                     .Select(field => allDtoProps.FirstOrDefault(p => string.Equals(p.Name, field, StringComparison.InvariantCultureIgnoreCase)))
                                     .Where(prop => prop != null)
                                     .ToList();

                return(mappedResult
                       .Select(dto =>
                {
                    var newDto = new TDto();
                    foreach (var prop in requestedProps)
                    {
                        prop.SetValue(newDto, prop.GetValue(dto));
                    }
                    return newDto;
                })
                       .ToList());
            }

            return(mappedResult);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Applies any applicable sorting to the query.
        /// If the client has specified any sorting (found in ListParameters.OrderByList),
        /// this will delegate to ApplyListClientSpecifiedSorting.
        /// Otherwise, this will delegate to ApplyListDefaultSorting.
        /// This is called by GetListAsync when constructing a list result.
        /// </summary>
        /// <param name="query">The query to sort.</param>
        /// <param name="parameters">The parameters by which to filter and paginate.</param>
        /// <returns>The new query with additional sorting applied.</returns>
        public virtual IQueryable <T> ApplyListSorting(IQueryable <T> query, IListParameters parameters)
        {
            var orderByParams = parameters.OrderByList;

            if (orderByParams.Any())
            {
                return(ApplyListClientSpecifiedSorting(query, parameters));
            }
            else
            {
                return(ApplyListDefaultSorting(query));
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Get a mapped list of results using all the behaviors defined in the data source.
        /// </summary>
        /// <typeparam name="TDto">The IClassDto to map the data to.</typeparam>
        /// <returns>A ListResult containing the desired data mapped to the desired type.</returns>
        public virtual async Task <ListResult <TDto> > GetMappedListAsync <TDto>(IListParameters parameters)
            where TDto : IClassDto <T>, new()
        {
            var(result, tree) = await GetListAsync(parameters);

            if (!result.WasSuccessful || result.List == null)
            {
                return(new ListResult <TDto>(result));
            }

            TransformResults(new ReadOnlyCollection <T>(result.List), parameters);

            var          mappingContext = new MappingContext(Context.User, parameters.Includes);
            IList <TDto> mappedResult   = result.List.Select(obj => Mapper.MapToDto <T, TDto>(obj, mappingContext, tree)).ToList();

            mappedResult = TrimListFields(mappedResult, parameters);

            return(new ListResult <TDto>(result, mappedResult));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Applies paging to the query as specified by ListParameters.Page and PageSize.
        /// This is called by GetListAsync when constructing a list result.
        /// </summary>
        /// <param name="query">The query to filter.</param>
        /// <param name="parameters">The parameters by which to paginate.</param>
        /// <param name="totalCount">A known total count of results for the query, for limiting the maximum page.</param>
        /// <param name="page">out: The page number that was skipped to.</param>
        /// <param name="pageSize">out: The page size that was used in paging.</param>
        /// <returns></returns>
        public virtual IQueryable <T> ApplyListPaging(IQueryable <T> query, IListParameters parameters, int?totalCount, out int page, out int pageSize)
        {
            page     = parameters.Page ?? 1;
            pageSize = parameters.PageSize ?? DefaultPageSize;
            pageSize = Math.Min(pageSize, MaxPageSize);
            pageSize = Math.Max(pageSize, 1);

            // Cap the page number at the last item
            if (totalCount.HasValue && (page - 1) * pageSize > totalCount)
            {
                page = (int)((totalCount - 1) / pageSize) + 1;
            }

            if (page > 1)
            {
                query = query.Skip((page - 1) * pageSize);
            }

            query = query.Take(pageSize);
            return(query);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Get an unmapped list of results using all the behaviors defined in the DataSource.
        /// </summary>
        /// <returns>A ListResult with the requested data and paging information,
        /// and an IncludeTree to be used when mapping/serializing the data.</returns>
        public virtual async Task <(ListResult <T> List, IncludeTree IncludeTree)> GetListAsync(IListParameters parameters)
        {
            var query = GetQuery(parameters);

            query = ApplyListFiltering(query, parameters);

            // Get a count
            int totalCount = await GetListTotalCountAsync(query, parameters);

            // Add paging, sorting only after we've gotten the total count, since they don't affect counts.
            query = ApplyListSorting(query, parameters);
            query = ApplyListPaging(query, parameters, totalCount, out int page, out int pageSize);

            var      canUseAsync = CanEvalQueryAsynchronously(query);
            List <T> result      = canUseAsync ? await query.ToListAsync() : query.ToList();

            var tree = GetIncludeTree(query, parameters);

            return(new ListResult <T>(result, page: page, totalCount: totalCount, pageSize: pageSize), tree);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Applies user-specified sorting to the query.
        /// These sort parameters may be found in ListParameters.OrderByList.
        /// This is called by ApplyListSorting when constructing a list result.
        /// </summary>
        /// <param name="query">The query to sort.</param>
        /// <param name="parameters">The parameters by which to filter.</param>
        /// <returns>The new query with additional sorting applied.</returns>
        public virtual IQueryable <T> ApplyListClientSpecifiedSorting(IQueryable <T> query, IListParameters parameters)
        {
            var orderByParams = parameters.OrderByList;

            if (!orderByParams.Any(p => p.Key == "none"))
            {
                var clauses = orderByParams
                              .Select(orderByParam =>
                {
                    string fieldName = orderByParam.Key;
                    string direction = orderByParam.Value.ToString();

                    // Validate that the field accessor is a valid property
                    // that the current user is allowed to read.
                    var parts = fieldName.Split('.');
                    PropertyViewModel prop = null;
                    foreach (var part in parts)
                    {
                        if (prop != null && !prop.IsPOCO)
                        {
                            // We're accessing a nested prop, but the parent isn't an object,
                            // so this can't be valid.
                            return(null);
                        }

                        prop = (prop?.Object ?? ClassViewModel).PropertyByName(part);

                        // Check if the new prop exists and is readable by user.
                        if (prop == null || !prop.IsClientProperty || !prop.SecurityInfo.IsReadable(User))
                        {
                            return(null);
                        }

                        // If the prop is an object that isn't readable, then this is no good.
                        if (prop.IsPOCO && !prop.Object.SecurityInfo.IsReadAllowed(User))
                        {
                            return(null);
                        }
                    }

                    if (prop.IsPOCO)
                    {
                        // The property is a POCO, not a value.
                        // Get the default order by for the object's type to figure out what field to sort by.
                        string clause = prop.Type.ClassViewModel.DefaultOrderByClause($"{fieldName}.");

                        // The default order by clause has an order associated, but we want to override it
                        // with the order that the client specified. A string replacement will do.
                        return(clause
                               .Replace("ASC", direction.ToUpper())
                               .Replace("DESC", direction.ToUpper()));
                    }
                    else
                    {
                        // We've validated that `fieldName` is a valid acccessor for a comparable property,
                        // and that the user is allowed to read it.
                        return($"{fieldName} {direction}");
                    }
                })
                              // Take all the clauses up until an invalid one is found.
                              .TakeWhile(clause => clause != null)
                              .ToList();

                if (clauses.Any())
                {
                    query = query.OrderBy(string.Join(", ", clauses));
                }
            }

            return(query);
        }
 public void AppendListIdentifierParameter(StringBuilder query, IListParameters parameters)
 {
     AppendListIdentifierParameter(query, parameters.List);
 }