using System; using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; namespace UserManagement.Repository { public static class IQueryableExtensions { public static IQueryable ApplySort(this IQueryable source, string orderBy, Dictionary mappingDictionary) { if (source == null) { throw new ArgumentNullException("source"); } if (mappingDictionary == null) { throw new ArgumentNullException("mappingDictionary"); } if (string.IsNullOrWhiteSpace(orderBy)) { return source; } // the orderBy string is separated by ",", so we split it. var orderByAfterSplit = orderBy.Split(','); // apply each orderby clause in reverse order - otherwise, the // IQueryable will be ordered in the wrong order foreach (var orderByClause in orderByAfterSplit.Reverse()) { // trim the orderByClause, as it might contain leading // or trailing spaces. Can't trim the var in foreach, // so use another var. var trimmedOrderByClause = orderByClause.Trim(); // if the sort option ends with with " desc", we order // descending, otherwise ascending var orderDescending = trimmedOrderByClause.EndsWith(" desc"); // remove " asc" or " desc" from the orderByClause, so we // get the property name to look for in the mapping dictionary var indexOfFirstSpace = trimmedOrderByClause.IndexOf(" "); var propertyName = indexOfFirstSpace == -1 ? trimmedOrderByClause : trimmedOrderByClause.Remove(indexOfFirstSpace); // find the matching property if (!mappingDictionary.ContainsKey(propertyName)) { throw new ArgumentException($"Key mapping for {propertyName} is missing"); } // get the PropertyMappingValue var propertyMappingValue = mappingDictionary[propertyName]; if (propertyMappingValue == null) { throw new ArgumentNullException("propertyMappingValue"); } // Run through the property names in reverse // so the orderby clauses are applied in the correct order foreach (var destinationProperty in propertyMappingValue.DestinationProperties.Reverse()) { // revert sort order if necessary if (propertyMappingValue.Revert) { orderDescending = !orderDescending; } source = source.OrderBy(destinationProperty + (orderDescending ? " descending" : " ascending")); } } return source; } public static IQueryable ShapeData(this IQueryable source, string fields, Dictionary mappingDictionary) { if (source == null) { throw new ArgumentNullException("source"); } if (mappingDictionary == null) { throw new ArgumentNullException("mappingDictionary"); } if (string.IsNullOrWhiteSpace(fields)) { return (IQueryable)source; } // ignore casing fields = fields.ToLower(); // the field are separated by ",", so we split it. var fieldsAfterSplit = fields.Split(','); // select clause starts with "new" - will create anonymous objects var selectClause = "new ("; // run through the fields foreach (var field in fieldsAfterSplit) { // trim each field, as it might contain leading // or trailing spaces. Can't trim the var in foreach, // so use another var. var propertyName = field.Trim(); // find the matching property if (!mappingDictionary.ContainsKey(propertyName)) { throw new ArgumentException($"Key mapping for {propertyName} is missing"); } // get the PropertyMappingValue var propertyMappingValue = mappingDictionary[propertyName]; if (propertyMappingValue == null) { throw new ArgumentNullException("propertyMappingValue"); } // Run through the destination property names foreach (var destinationProperty in propertyMappingValue.DestinationProperties) { // add to select clause selectClause += $" {destinationProperty},"; } } // remove last comma, add closing arrow and execute select clause selectClause = selectClause.Substring(0, selectClause.Length - 1) + ")"; return (IQueryable)source.Select(selectClause); } } }