using Marco.Pms.Model.Filters; using System.Data; using System.Linq.Dynamic.Core; namespace Marco.Pms.Services.Extensions { /// /// Enterprise-grade extension methods for applying dynamic filters and sorting to IQueryable sources. /// public static class QueryableExtensions { public static IQueryable ApplyCustomFilters(this IQueryable query, AdvanceFilter? filter, string defaultSortColumn) { // 1. Apply Advanced Filters (Arithmetic/Logic) if (filter?.AdvanceFilters != null && filter.AdvanceFilters.Any()) { foreach (var advanceFilter in filter.AdvanceFilters) { if (string.IsNullOrWhiteSpace(advanceFilter.Column)) continue; string op = advanceFilter.Opration.ToLower().Trim(); string predicate = ""; // Map your custom strings to Dynamic LINQ operators switch (op) { case "greater than": predicate = $"{advanceFilter.Column} > @0"; break; case "less than": predicate = $"{advanceFilter.Column} < @0"; break; case "equal to": predicate = $"{advanceFilter.Column} == @0"; break; case "not equal": predicate = $"{advanceFilter.Column} != @0"; break; case "greater or equal": predicate = $"{advanceFilter.Column} >= @0"; break; case "smaller or equal": predicate = $"{advanceFilter.Column} <= @0"; break; default: continue; } if (!string.IsNullOrEmpty(predicate)) { // Dynamic LINQ handles type conversion (string "100" to int 100) automatically query = query.Where(predicate, advanceFilter.Value); } } } // 2. Apply Sorting if (filter?.SortFilters != null && filter.SortFilters.Any()) { // Build a comma-separated sort string: "Column1 desc, Column2 asc" var sortExpressions = new List(); foreach (var sort in filter.SortFilters) { string direction = sort.SortDescending ? "desc" : "asc"; sortExpressions.Add($"{sort.Column} {direction}"); } query = query.OrderBy(string.Join(", ", sortExpressions)); } else { // Default sorting query = query.OrderBy($"{defaultSortColumn} desc"); } // 3.Apply GroupBy if (!string.IsNullOrEmpty(filter?.GroupByColumn)) { query.GroupBy(filter.GroupByColumn, "it") .Select("new (Key, it as Items)"); // Reshape to { Key: "Value", Items: [...] } } return query; } /// /// Applies search filters to the given IQueryable. /// /// The type of the elements in the IQueryable. /// The IQueryable to apply the filters to. /// The list of search filters to apply. /// The filtered IQueryable. public static IQueryable ApplySearchFilters(this IQueryable query, List searchFilters) { // Apply search filters to the query if (searchFilters.Any()) { foreach (var search in searchFilters) { if (string.IsNullOrWhiteSpace(search.Column) || string.IsNullOrWhiteSpace(search.Value)) continue; // Generates: x.Column.Contains("Value") // Case insensitive logic can be handled here if needed query = query.Where($"{search.Column}.Contains(@0)", search.Value); } } return query; } /// /// Applies group by filters to the given IQueryable. /// /// The type of the elements in the IQueryable. /// The IQueryable to apply the filters to. /// The column to group by. /// The grouped IQueryable. public static IQueryable ApplyGroupByFilters(this IQueryable query, string groupByColumn) { // Group the query by the specified column and reshape the result to { Key: "Value", Items: [...] } query.GroupBy(groupByColumn, "it") .Select("new (Key, it as Items)"); return query; } /// /// Applies list filters to the given IQueryable. /// /// The type of the elements in the IQueryable. /// The IQueryable to apply the filters to. /// The list of filters to apply. /// The filtered IQueryable. public static IQueryable ApplyListFilters(this IQueryable query, List filters) { // Check if there are any filters if (filters == null || !filters.Any()) return query; // Apply filters to the query foreach (var filter in filters) { // Skip if column is empty or values are null or empty if (string.IsNullOrWhiteSpace(filter.Column) || filter.Values == null || !filter.Values.Any()) continue; // Apply filter to the query query = query.Where($"@0.Contains({filter.Column})", filter.Values); } // Return the filtered query return query; } /// /// Applies date filters to the given IQueryable. /// /// The type of the elements in the IQueryable. /// The IQueryable to apply the filters to. /// The date filter to apply. /// The filtered IQueryable. public static IQueryable ApplyDateFilter(this IQueryable query, DateDynamicFilter dateFilter) { // Check if date filter is null or column is empty if (dateFilter == null || string.IsNullOrWhiteSpace(dateFilter.Column)) return query; // Convert start and end values to date var startValue = dateFilter.StartValue.Date; var endValue = dateFilter.EndValue.Date.AddDays(1); // Apply a filter to include items with a date greater than or equal to the start value query = query.Where($"{dateFilter.Column} >= @0", startValue); // Apply a filter to include items with a date less than or equal to the end value query = query.Where($"{dateFilter.Column} < @0", endValue); // Return the filtered IQueryable return query; } } }