/// <summary>
        /// Applies the given DynamicQueryOptions to the generic IEnumerable instace.
        /// </summary>
        /// <param name="currentSet">Existing IEnumerable instance.</param>
        /// <param name="dynamicQueryOptions">Query options to apply.</param>
        /// <returns>DynamicQueryOptions applied IEnumerable instance,</returns>
        public static IQueryable ApplyFilters(this IQueryable currentSet, DynamicQueryOptions dynamicQueryOptions)
        {
            try
            {
                if (dynamicQueryOptions == null || currentSet == null)
                {
                    return(currentSet);
                }

                Expression exp = null;

                // Create the query parameter
                ParameterExpression param = Expression.Parameter(currentSet.ElementType, currentSet.ElementType.Name.ToLower());
                if (dynamicQueryOptions.Filters != null && dynamicQueryOptions.Filters.Count > 0)
                {
                    // Copy the array since we need to mutate it, we should avoid mutating the real list.
                    List <Filter> dqbFilters = dynamicQueryOptions.Filters.ToList();

                    // Since the expression is null at this point, we should create it with our first filter.
                    exp = BuildFilterExpression(param, dqbFilters.FirstOrDefault(), dynamicQueryOptions.UsesCaseInsensitiveSource);
                    dqbFilters.RemoveAt(0); // Remove the first since it was added already.

                    // Append the rest
                    foreach (Filter item in dqbFilters)
                    {
                        exp = Expression.AndAlso(exp, BuildFilterExpression(param, item, dynamicQueryOptions.UsesCaseInsensitiveSource));
                    }
                }

                if (dynamicQueryOptions.SortOptions != null && dynamicQueryOptions.SortOptions.Count > 0)
                {
                    List <OrderOptionDetails> orderLambdas = new List <OrderOptionDetails>();
                    foreach (SortOption so in dynamicQueryOptions.SortOptions)
                    {
                        Expression paramExpr = ExtractMember(param, so.PropertyName);
                        orderLambdas.Add(new OrderOptionDetails
                        {
                            Direction           = so.SortingDirection,
                            Expression          = Expression.Lambda(paramExpr, param),
                            ParameterExpression = paramExpr,
                            CaseSensitive       = so.CaseSensitive
                        });
                    }

                    var orderVisitor = new OrderFunctionVisitor(
                        currentSet.Expression,
                        orderLambdas,
                        currentSet.ElementType,
                        dynamicQueryOptions.UsesCaseInsensitiveSource,
                        dynamicQueryOptions.IgnorePredefinedOrders);

                    currentSet = currentSet.Provider.CreateQuery(orderVisitor.ApplyOrders());
                }

                if (exp != null)
                {
                    MethodCallExpression whereFilter = Expression.Call(
                        LINQUtils.BuildLINQExtensionMethod(
                            nameof(Enumerable.Where),
                            genericElementTypes: new[] { currentSet.ElementType },
                            enumerableType: typeof(Queryable)),
                        currentSet.Expression,
                        Expression.Quote(Expression.Lambda(exp, param)));

                    currentSet = currentSet.Provider.CreateQuery(whereFilter);
                }

                if (dynamicQueryOptions.PaginationOption != null)
                {
                    if (dynamicQueryOptions.PaginationOption.AssignDataSetCount)
                    {
                        dynamicQueryOptions.PaginationOption.DataSetCount = (int)_countFunction.Invoke(null, new[] { currentSet });
                    }

                    if (dynamicQueryOptions.PaginationOption.Offset > 0)
                    {
                        MethodCallExpression skip = Expression.Call(
                            _skipFunction,
                            currentSet.Expression,
                            Expression.Constant(dynamicQueryOptions.PaginationOption.Offset));

                        currentSet = currentSet.Provider.CreateQuery(skip);
                    }

                    if (dynamicQueryOptions.PaginationOption.Count > 0)
                    {
                        MethodCallExpression take = Expression.Call(
                            _takeFunction,
                            currentSet.Expression,
                            Expression.Constant(dynamicQueryOptions.PaginationOption.Count));

                        currentSet = currentSet.Provider.CreateQuery(take);
                    }
                }

                return(currentSet);
            }
            catch (Exception ex)
            {
                throw new DynamicQueryException("DynamicQueryBuilder has encountered an unhandled exception", string.Empty, ex);
            }
        }
        /// <summary>
        /// Applies the given DynamicQueryOptions to the generic IEnumerable instace.
        /// </summary>
        /// <param name="currentSet">Existing IEnumerable instance.</param>
        /// <param name="dynamicQueryOptions">Query options to apply.</param>
        /// <returns>DynamicQueryOptions applied IEnumerable instance,</returns>
        public static IQueryable ApplyFilters(this IQueryable currentSet, DynamicQueryOptions dynamicQueryOptions)
        {
            try
            {
                if (dynamicQueryOptions == null || currentSet == null)
                {
                    return(currentSet);
                }

                Expression exp = null;

                // Create the query parameter (x =>)
                ParameterExpression param = Expression.Parameter(currentSet.ElementType, currentSet.ElementType.Name.ToLower());

                // Check if we have any filters
                if (dynamicQueryOptions.Filters != null && dynamicQueryOptions.Filters.Count > 0)
                {
                    // Lets build the first expression and then iterate the rest and append them to this one
                    exp = BuildFilterExpression(param,
                                                dynamicQueryOptions.Filters.First(),
                                                dynamicQueryOptions.UsesCaseInsensitiveSource);

                    // We start to iterate with the second element here because we have just built the first expression up above
                    for (int i = 1; i < dynamicQueryOptions.Filters.Count; ++i)
                    {
                        // Build the current expression
                        Expression builtExpression = BuildFilterExpression(param,
                                                                           dynamicQueryOptions.Filters[i],
                                                                           dynamicQueryOptions.UsesCaseInsensitiveSource);

                        // Get the previous filter to retrieve the logical operator between the current and the next filter
                        Filter previousFilter = dynamicQueryOptions.Filters.ElementAtOrDefault(i - 1);

                        exp = LINQUtils.BuildLINQLogicalOperatorExpression(previousFilter, exp, builtExpression);
                    }
                }

                if (dynamicQueryOptions.SortOptions != null && dynamicQueryOptions.SortOptions.Count > 0)
                {
                    var orderLambdas = new List <OrderOptionDetails>();
                    foreach (SortOption so in dynamicQueryOptions.SortOptions)
                    {
                        Expression paramExpr = ExtractMember(param, so.PropertyName, false);
                        orderLambdas.Add(new OrderOptionDetails
                        {
                            Direction           = so.SortingDirection,
                            Expression          = Expression.Lambda(paramExpr, param),
                            ParameterExpression = paramExpr,
                            CaseSensitive       = so.CaseSensitive
                        });
                    }

                    var orderVisitor = new OrderFunctionVisitor(
                        currentSet.Expression,
                        orderLambdas,
                        currentSet.ElementType,
                        dynamicQueryOptions.UsesCaseInsensitiveSource,
                        dynamicQueryOptions.IgnorePredefinedOrders);

                    currentSet = currentSet.Provider.CreateQuery(orderVisitor.ApplyOrders());
                }

                if (exp != null)
                {
                    MethodCallExpression whereFilter = Expression.Call(
                        LINQUtils.BuildLINQExtensionMethod(
                            nameof(Enumerable.Where),
                            genericElementTypes: new[] { currentSet.ElementType },
                            enumerableType: typeof(Queryable)),
                        currentSet.Expression,
                        Expression.Quote(Expression.Lambda(exp, param)));

                    currentSet = currentSet.Provider.CreateQuery(whereFilter);
                }

                if (dynamicQueryOptions.PaginationOption != null)
                {
                    if (dynamicQueryOptions.PaginationOption.AssignDataSetCount)
                    {
                        dynamicQueryOptions.PaginationOption.DataSetCount = (int)ExtensionMethods.CountFunction.Invoke(null, new[] { currentSet });
                    }

                    if (dynamicQueryOptions.PaginationOption.Offset > 0)
                    {
                        MethodCallExpression skip = Expression.Call(
                            ExtensionMethods.SkipFunction,
                            currentSet.Expression,
                            Expression.Constant(dynamicQueryOptions.PaginationOption.Offset));

                        currentSet = currentSet.Provider.CreateQuery(skip);
                    }

                    if (dynamicQueryOptions.PaginationOption.Count > 0)
                    {
                        MethodCallExpression take = Expression.Call(
                            ExtensionMethods.TakeFunction,
                            currentSet.Expression,
                            Expression.Constant(dynamicQueryOptions.PaginationOption.Count));

                        currentSet = currentSet.Provider.CreateQuery(take);
                    }
                }

                return(currentSet);
            }
            catch (Exception ex)
            {
                throw new DynamicQueryException("DynamicQueryBuilder has encountered an unhandled exception", string.Empty, ex);
            }
        }