/// <summary>
        /// Convert the <see cref="IQueryable{T}"/> into paginated list.
        /// </summary>
        /// <typeparam name="T">Type of the <see cref="IQueryable"/>.</typeparam>
        /// <param name="source">The type to be extended.</param>
        /// <param name="pageIndex">The current page index.</param>
        /// <param name="pageSize">Size of the pagiantion.</param>
        /// <returns>Returns <see cref="PaginatedList{T}"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="pageIndex"/> is smaller than 1.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="pageSize"/> is smaller than 1.</exception>
        public static async Task <PaginatedList <T> > ToPaginatedListAsync <T>(
            this IQueryable <T> source,
            PaginationSpecification <T> specification)
            where T : class
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (specification == null)
            {
                throw new ArgumentNullException(nameof(specification));
            }

            IQueryable <T> countSource = source;

            // modify the IQueryable using the specification's criteria expression
            if (specification.Conditions != null && specification.Conditions.Any())
            {
                foreach (Expression <Func <T, bool> > conditon in specification.Conditions)
                {
                    countSource = source.Where(conditon);
                }
            }

            long count = await countSource.LongCountAsync();

            source = source.GetSpecifiedQuery(specification);
            List <T> items = await source.ToListAsync();

            PaginatedList <T> paginatedList = new PaginatedList <T>(items, count, specification.PageIndex, specification.PageSize);

            return(paginatedList);
        }
        public async Task <PaginatedList <T> > GetListAsync <T>(
            PaginationSpecification <T> specification,
            CancellationToken cancellationToken = default)
            where T : class
        {
            if (specification == null)
            {
                throw new ArgumentNullException(nameof(specification));
            }

            PaginatedList <T> paginatedList = await _dbContext.Set <T>().ToPaginatedListAsync(specification, cancellationToken);

            return(paginatedList);
        }
        /// <summary>
        /// Convert the <see cref="IQueryable{T}"/> into paginated list.
        /// </summary>
        /// <typeparam name="T">Type of the <see cref="IQueryable"/>.</typeparam>
        /// <param name="source">The type to be extended.</param>
        /// <param name="specification">An object of <see cref="PaginationSpecification{T}"/>.</param>
        /// <param name="cancellationToken"> A <see cref="CancellationToken"/> to observe while waiting for the task to complete.</param>
        /// <returns>Returns <see cref="Task"/> of <see cref="PaginatedList{T}"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="specification"/> is smaller than 1.</exception>
        public static async Task <PaginatedList <T> > ToPaginatedListAsync <T>(
            this IQueryable <T> source,
            PaginationSpecification <T> specification,
            CancellationToken cancellationToken = default)
            where T : class
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (specification == null)
            {
                throw new ArgumentNullException(nameof(specification));
            }

            if (specification.PageIndex < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(specification.PageIndex), $"The value of {nameof(specification.PageIndex)} must be greater than 0.");
            }

            if (specification.PageSize < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(specification.PageSize), $"The value of {nameof(specification.PageSize)} must be greater than 0.");
            }

            IQueryable <T> countSource = source;

            // modify the IQueryable using the specification's expression criteria
            if (specification.Conditions != null && specification.Conditions.Any())
            {
                foreach (Expression <Func <T, bool> > conditon in specification.Conditions)
                {
                    countSource = source.Where(conditon);
                }
            }

            long count = await countSource.LongCountAsync(cancellationToken);

            source = source.GetSpecifiedQuery(specification);
            List <T> items = await source.ToListAsync(cancellationToken);

            PaginatedList <T> paginatedList = new PaginatedList <T>(items, count, specification.PageIndex, specification.PageSize);

            return(paginatedList);
        }
        public async Task <PaginatedList <TProjectedType> > GetListAsync <T, TProjectedType>(
            PaginationSpecification <T> specification,
            Expression <Func <T, TProjectedType> > selectExpression,
            CancellationToken cancellationToken = default)
            where T : class
            where TProjectedType : class
        {
            if (specification == null)
            {
                throw new ArgumentNullException(nameof(specification));
            }

            if (selectExpression == null)
            {
                throw new ArgumentNullException(nameof(selectExpression));
            }

            IQueryable <T> query = _dbContext.Set <T>().GetSpecifiedQuery((SpecificationBase <T>)specification);

            PaginatedList <TProjectedType> paginatedList = await query.Select(selectExpression)
                                                           .ToPaginatedListAsync(specification.PageIndex, specification.PageSize, cancellationToken);

            return(paginatedList);
        }
        public static IQueryable <T> GetSpecifiedQuery <T>(this IQueryable <T> inputQuery, PaginationSpecification <T> specification)
            where T : class
        {
            if (inputQuery == null)
            {
                throw new ArgumentNullException(nameof(inputQuery));
            }

            if (specification == null)
            {
                throw new ArgumentNullException(nameof(specification));
            }

            if (specification.PageIndex < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(specification.PageIndex), "The value of pageIndex must be greater than 0.");
            }

            if (specification.PageSize < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(specification.PageSize), "The value of pageSize must be greater than 0.");
            }

            IQueryable <T> query = GetSpecifiedQuery(inputQuery, (SpecificationBase <T>)specification);

            // Apply paging if enabled
            int skip = (specification.PageIndex - 1) * specification.PageSize;

            query = query.Skip(skip).Take(specification.PageSize);

            return(query);
        }