예제 #1
0
        private static IQueryable FilterResponse(GridDataRequest request, IQueryable subset, GridDataResponse response)
        {
            var isDbQuery = subset.GetType().GetTypeInfo().IsGenericType&&
                            subset.GetType().GetInterfaces().Any(y => y == typeof(IListSource));

            // Perform Searching
            var searchLambda    = new StringBuilder();
            var searchParamArgs = new List <object>();
            var searchValue     = isDbQuery ? request.Search.Text : request.Search.Text.ToLowerInvariant();

            switch (request.Search.Operator)
            {
            case CompareOperators.Auto:
                var filter = string.Empty;
                var values = new List <object>();

                if (request.Columns.Any(x => x.Searchable))
                {
                    filter = "(";
                }

                foreach (var column in request.Columns.Where(x => x.Searchable))
                {
                    filter += string.Format(isDbQuery
                            ? "{0}.Contains(@{1}) ||"
                            : "({0} != null && {0}.ToLowerInvariant().Contains(@{1})) ||", column.Name, values.Count);

                    values.Add(searchValue);
                }

                if (string.IsNullOrEmpty(filter) == false)
                {
                    searchLambda.Append(filter.Remove(filter.Length - 3, 3) + ") &&");
                    searchParamArgs.AddRange(values);
                }

                break;
            }

            // Perform Filtering
            foreach (var column in request.Columns.Where(x => x.Filter != null))
            {
                if (string.IsNullOrWhiteSpace(column.Filter.Text) && column.Filter.Argument == null)
                {
                    continue; // TODO: Handle null?
                }
                column.Filter.HasFilter = true;

                switch (column.Filter.Operator)
                {
                case CompareOperators.Equals:
                case CompareOperators.NotEquals:
                    if (string.IsNullOrWhiteSpace(column.Filter.Text))
                    {
                        continue;
                    }

                    if (column.DataType == DataType.Date)
                    {
                        searchLambda.AppendFormat(
                            column.Filter.Operator == CompareOperators.Equals
                                    ? "({0} >= @{1} && {0} <= @{2}) &&"
                                    : "({0} < @{1} || {0} > @{2}) &&", column.Name,
                            searchParamArgs.Count, searchParamArgs.Count + 1);
                    }
                    else
                    {
                        searchLambda.AppendFormat("{0} {2} @{1} &&", column.Name, searchParamArgs.Count,
                                                  GetSqlOperator(column.Filter.Operator));
                    }

                    if (column.DataType == DataType.Numeric)
                    {
                        searchParamArgs.Add(decimal.Parse(column.Filter.Text));
                    }
                    else if (column.DataType == DataType.DateTime || column.DataType == DataType.DateTimeUtc)
                    {
                        searchParamArgs.Add(DateTime.Parse(column.Filter.Text));
                    }
                    else if (column.DataType == DataType.Date)
                    {
                        searchParamArgs.Add(DateTime.Parse(column.Filter.Text).Date);
                        searchParamArgs.Add(DateTime.Parse(column.Filter.Text).Date.AddDays(1).AddMinutes(-1));
                    }
                    else if (column.DataType == DataType.Boolean)
                    {
                        searchParamArgs.Add(bool.Parse(column.Filter.Text));
                    }
                    else
                    {
                        searchParamArgs.Add(column.Filter.Text);
                    }

                    break;

                case CompareOperators.Contains:
                    searchLambda.AppendFormat(
                        isDbQuery
                                ? "{0}.Contains(@{1}) &&"
                                : "({0} != null && {0}.ToLowerInvariant().Contains(@{1})) &&", column.Name,
                        searchParamArgs.Count);

                    searchParamArgs.Add(column.Filter.Text.ToLowerInvariant());
                    break;

                case CompareOperators.StartsWith:
                    searchLambda.AppendFormat(
                        isDbQuery
                                ? "{0}.StartsWith(@{1}) &&"
                                : "({0} != null && {0}.ToLowerInvariant().StartsWith(@{1})) &&", column.Name,
                        searchParamArgs.Count);

                    searchParamArgs.Add(column.Filter.Text.ToLowerInvariant());
                    break;

                case CompareOperators.EndsWith:
                    searchLambda.AppendFormat(
                        isDbQuery
                                ? "{0}.EndsWith(@{1}) &&"
                                : "({0} != null && {0}.ToLowerInvariant().EndsWith(@{1})) &&", column.Name,
                        searchParamArgs.Count);

                    searchParamArgs.Add(column.Filter.Text.ToLowerInvariant());
                    break;

                case CompareOperators.NotContains:
                    searchLambda.AppendFormat(
                        isDbQuery
                                ? "{0}.Contains(@{1}) == false &&"
                                : "({0} != null && {0}.ToLowerInvariant().Contains(@{1}) == false) &&", column.Name,
                        searchParamArgs.Count);

                    searchParamArgs.Add(column.Filter.Text.ToLowerInvariant());
                    break;

                case CompareOperators.NotStartsWith:
                    searchLambda.AppendFormat(
                        isDbQuery
                                ? "{0}.StartsWith(@{1}) == false &&"
                                : "({0} != null && {0}.ToLowerInvariant().StartsWith(@{1}) == false) &&", column.Name,
                        searchParamArgs.Count);

                    searchParamArgs.Add(column.Filter.Text.ToLowerInvariant());
                    break;

                case CompareOperators.NotEndsWith:
                    searchLambda.AppendFormat(
                        isDbQuery
                                ? "{0}.EndsWith(@{1}) == false &&"
                                : "({0} != null && {0}.ToLowerInvariant().EndsWith(@{1}) == false) &&", column.Name,
                        searchParamArgs.Count);

                    searchParamArgs.Add(column.Filter.Text.ToLowerInvariant());
                    break;

                case CompareOperators.Gte:
                case CompareOperators.Gt:
                case CompareOperators.Lte:
                case CompareOperators.Lt:
                    searchLambda.AppendFormat("{0} {2} @{1} &&", column.Name, searchParamArgs.Count,
                                              GetSqlOperator(column.Filter.Operator));

                    if (column.DataType == DataType.Numeric)
                    {
                        searchParamArgs.Add(decimal.Parse(column.Filter.Text));
                    }
                    else
                    {
                        searchParamArgs.Add(DateTime.Parse(column.Filter.Text));
                    }

                    break;

                case CompareOperators.Multiple:
                    if (column.Filter.Argument == null || column.Filter.Argument.Length == 0)
                    {
                        continue;
                    }

                    var filterString = "(";
                    foreach (var filter in column.Filter.Argument)
                    {
                        filterString += string.Format(" {0} == @{1} ||", column.Name, searchParamArgs.Count);
                        searchParamArgs.Add(filter);
                    }

                    if (filterString.Length == 1)
                    {
                        continue;
                    }

                    searchLambda.AppendFormat(filterString.Remove(filterString.Length - 3, 3) + ") &&");

                    break;

                case CompareOperators.Between:
                    if (column.Filter.Argument == null || column.Filter.Argument.Length == 0)
                    {
                        continue;
                    }

                    searchLambda.AppendFormat("(({0} >= @{1}) &&  ({0} <= @{2})) &&", column.Name,
                                              searchParamArgs.Count, searchParamArgs.Count + 1);

                    if (column.DataType == DataType.Numeric)
                    {
                        searchParamArgs.Add(decimal.Parse(column.Filter.Text));
                        searchParamArgs.Add(decimal.Parse(column.Filter.Argument[0]));
                    }
                    else
                    {
                        searchParamArgs.Add(DateTime.Parse(column.Filter.Text));
                        searchParamArgs.Add(DateTime.Parse(column.Filter.Argument[0]));
                    }

                    break;
                }
            }

            if (searchLambda.Length > 0)
            {
                subset = subset.Where(searchLambda.Remove(searchLambda.Length - 3, 3).ToString(),
                                      searchParamArgs.ToArray());

                if (subset != null)
                {
                    response.FilteredRecordCount = subset.Count();
                }
            }

            return(subset);
        }
예제 #2
0
        /// <summary>
        /// Generates a GridDataResponse using the GridDataRequest and an IQueryable source,
        /// like a DataSet in Entity Framework.
        /// </summary>
        /// <param name="request">The Tubular Grid Request.</param>
        /// <param name="dataSource">The IQueryable source.</param>
        /// <param name="preProcessSubset">The subset's process delegate.</param>
        /// <returns>A grid response.</returns>
        public static GridDataResponse CreateGridDataResponse(
            this GridDataRequest request,
            IQueryable dataSource,
            ProcessResponseSubset?preProcessSubset = null)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (request.Columns.Any() != true)
            {
                throw new ArgumentOutOfRangeException(nameof(request), "Missing column information");
            }

            var response = new GridDataResponse
            {
                Counter             = request.Counter,
                TotalRecordCount    = dataSource.Count(),
                FilteredRecordCount = dataSource.Count(),
            };

            var properties = dataSource.ElementType.ExtractProperties();
            var columnMap  = MapColumnsToProperties(request.Columns, properties);

            var subset = FilterResponse(request, dataSource, response);

            // Perform Sorting
            var orderingExpression = request.Columns.Where(x => x.SortOrder > 0)
                                     .OrderBy(x => x.SortOrder)
                                     .Aggregate(string.Empty,
                                                (current, column) =>
                                                current +
                                                (column.Name + " " + (column.SortDirection == SortDirection.Ascending ? "ASC" : "DESC") +
                                                 ", "));

            // Apply the sorting expression if supplied
            subset = !string.IsNullOrWhiteSpace(orderingExpression)
                ? subset.OrderBy(orderingExpression.Substring(0, orderingExpression.Length - 2))
                : subset.OrderBy($"{request.Columns.First().Name} ASC");

            // Check aggregations before paging
            // Should it aggregate before filtering too?
            response.AggregationPayload = AggregateSubset(request.Columns, subset);

            var pageSize = request.Take;

            // Take with value -1 represents entire set
            if (request.Take == -1)
            {
                response.TotalPages  = 1;
                response.CurrentPage = 1;
                pageSize             = subset.Count();
                subset = subset.Skip(request.Skip);
            }
            else
            {
                var filteredCount = subset.Count();
                var totalPages    = (int)Math.Ceiling((double)filteredCount / pageSize);

                if (totalPages > 0)
                {
                    response.TotalPages = totalPages;
                    var currentPage = (request.Skip / pageSize) + 1;
                    response.CurrentPage = Math.Min(currentPage, totalPages);

                    if (request.Skip > 0)
                    {
                        var maxSkip = pageSize *
                                      (response.CurrentPage == response.TotalPages
                                          ? response.CurrentPage - 1
                                          : response.CurrentPage);

                        subset = subset.Skip(Math.Min(request.Skip, maxSkip));
                    }
                }
                else
                {
                    response.TotalPages  = 1;
                    response.CurrentPage = 1;
                }

                subset = subset.Take(pageSize);
            }

            // Generate the response data in a suitable format
            if (preProcessSubset != null)
            {
                subset = preProcessSubset(subset);
            }

            response.Payload = CreateGridPayload(subset, columnMap, pageSize, request.TimezoneOffset);
            return(response);
        }
예제 #3
0
        /// <summary>
        /// Generates a GridDataReponse using the GridDataRequest and an IQueryable source,
        /// like a DataSet in Entity Framework.
        /// </summary>
        /// <param name="request">The Tubular's grid request</param>
        /// <param name="dataSource">The IQueryable source</param>
        /// <param name="preProcessSubset">The subset's process delegate</param>
        /// <returns></returns>
        public static GridDataResponse CreateGridDataResponse(this GridDataRequest request, IQueryable dataSource,
                                                              ProcessResponseSubset preProcessSubset)
        {
            if (request == null)
            {
                throw new InvalidOperationException("The GridDataRequest is null");
            }

            var response = new GridDataResponse
            {
                Counter             = request.Counter,
                TotalRecordCount    = dataSource.Count(),
                FilteredRecordCount = dataSource.Count()
            };

            var properties = ExtractProperties(dataSource.ElementType);
            var columnMap  = MapColumnsToProperties(request.Columns, properties);

            var subset = FilterResponse(request, dataSource, response);


            // Perform Sorting
            var orderingExpression = string.Empty;

            foreach (var column in request.Columns.Where(x => x.SortOrder > 0).OrderBy(x => x.SortOrder))
            {
                orderingExpression += column.Name + " " +
                                      (column.SortDirection == SortDirection.Ascending ? "ASC" : "DESC") + ", ";
            }

            // Apply the sorting expression if supplied
            if (!string.IsNullOrWhiteSpace(orderingExpression))
            {
                subset = subset.OrderBy(orderingExpression.Substring(0, orderingExpression.Length - 2));
            }
            else
            {
                subset = subset.OrderBy(request.Columns.First().Name + " ASC");
            }

            // Check aggregations before paging
            // Should it aggregate before filtering too?
            response.AggregationPayload = new Dictionary <string, object>();

            foreach (var column in request.Columns.Where(x => x.Aggregate != AggregationFunction.None))
            {
                switch (column.Aggregate)
                {
                case AggregationFunction.Sum:
                    // we try to select the column as decimal? and sum it
                    if (subset.ElementType.GetProperty(column.Name).PropertyType == typeof(double))
                    {
                        response.AggregationPayload.Add(column.Name,
                                                        subset.Select(column.Name).Cast <double?>().Sum());
                    }
                    else
                    {
                        response.AggregationPayload.Add(column.Name,
                                                        subset.Select(column.Name).Cast <decimal?>().Sum());
                    }

                    break;

                case AggregationFunction.Average:
                    if (subset.ElementType.GetProperty(column.Name).PropertyType == typeof(double))
                    {
                        response.AggregationPayload.Add(column.Name,
                                                        subset.Select(column.Name).Cast <double?>().Average());
                    }
                    else
                    {
                        response.AggregationPayload.Add(column.Name,
                                                        subset.Select(column.Name).Cast <decimal?>().Average());
                    }

                    break;

                case AggregationFunction.Max:
                    if (subset.ElementType.GetProperty(column.Name).PropertyType == typeof(double))
                    {
                        response.AggregationPayload.Add(column.Name,
                                                        subset.Select(column.Name).Cast <double?>().Max());
                    }
                    else
                    {
                        response.AggregationPayload.Add(column.Name,
                                                        subset.Select(column.Name).Cast <decimal?>().Max());
                    }

                    break;

                case AggregationFunction.Min:
                    if (subset.ElementType.GetProperty(column.Name).PropertyType == typeof(double))
                    {
                        response.AggregationPayload.Add(column.Name,
                                                        subset.Select(column.Name).Cast <double?>().Min());
                    }
                    else
                    {
                        response.AggregationPayload.Add(column.Name,
                                                        subset.Select(column.Name).Cast <decimal?>().Min());
                    }

                    break;

                case AggregationFunction.Count:
                    response.AggregationPayload.Add(column.Name, subset.Select(column.Name).Cast <string>().Count());
                    break;

                case AggregationFunction.DistinctCount:
                    response.AggregationPayload.Add(column.Name,
                                                    subset.Select(column.Name).Cast <string>().Distinct().Count());
                    break;

                default:
                    response.AggregationPayload.Add(column.Name, 0);
                    break;
                }
            }

            var pageSize = request.Take;

            // Take with value -1 represents entire set
            if (request.Take == -1)
            {
                response.TotalPages  = 1;
                response.CurrentPage = 1;
                pageSize             = subset.Count();
                subset = subset.Skip(request.Skip);
            }
            else
            {
                response.TotalPages = (response.FilteredRecordCount + pageSize - 1) / pageSize;

                if (response.TotalPages > 0)
                {
                    response.CurrentPage = 1 +
                                           (int)
                                           Math.Truncate((request.Skip / (float)response.FilteredRecordCount) *
                                                         response.TotalPages);

                    if (response.CurrentPage > response.TotalPages)
                    {
                        response.CurrentPage = response.TotalPages;
                        request.Skip         = (response.CurrentPage - 1) * request.Take;
                    }

                    if (request.Skip < 0)
                    {
                        request.Skip = 0;
                    }

                    subset = subset.Skip(request.Skip);
                }

                subset = subset.Take(request.Take);
            }

            // Generate the response data in a suitable format
            if (preProcessSubset != null)
            {
                subset = preProcessSubset(subset);
            }

            response.Payload = CreateGridPayload(subset, columnMap, pageSize, request.TimezoneOffset);
            return(response);
        }