these guys:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
via the Newtonsoft.Json nuget package.
Entity in database describing a filter:
public partial class DisplayGroupDataFilter
{
public int Id { get; set; }
public int GroupId { get; set; }
public string FilterRoot { get; set; }
public string PropertyNameToFilterOn { get; set; }
public string FilterItemValues { get; set; }
public string FilterType { get; set; }
public bool Active { get; set; }
public virtual DisplayGroup DisplayGroup { get; set; }
}
Entity in database describing a sort:
public partial class DisplayGroupDataSort
{
public int Id { get; set; }
public int GroupId { get; set; }
public string Field { get; set; }
public string Direction { get; set; }
public bool Active { get; set; }
public int Order { get; set; }
public virtual DisplayGroup DisplayGroup { get; set; }
}
the DataService:
/// <summary>
/// applies filters and sort to supplied json data
/// </summary>
/// <param name="data">the json data</param>
/// <param name="dataFilters">collection of filters to apply to data</param>
/// <param name="dataSorts">collection of sorts to apply to data</param>
/// <returns></returns>
private string ApplManipulationsToGroupData(string data, List<DisplayGroupDataFilter> dataFilters, List<DisplayGroupDataSort> dataSorts)
{
JObject jdata = JObject.Parse(data);
foreach (var filter in dataFilters)
{
jdata = ApplyDataFilterToGroupData(jdata, filter);
}
if (dataSorts.Any())
{
ApplySortToGroupData(jdata, dataSorts);
}
return JsonConvert.SerializeObject(jdata);
}
private JObject ApplySortToGroupData(JObject data, List<DisplayGroupDataSort> dataSorts)
{
// get the collection we want to sort our of the data
JArray existing = (JArray)data.SelectToken("Location.Rows");
// create a custom comparer that understands how we want sort elements
var comparer = new JObjectSortComparer(dataSorts);
// sort the collection using our custom comparer
var sorted = existing.AsQueryable().OrderBy(obj => (JObject)obj, comparer);
// put the sorted collection back into the orginal data
data["Location"]["Rows"] = new JArray(sorted);
return data;
}
private JObject ApplyDataFilterToGroupData(JObject data, DisplayGroupDataFilter dataFilter)
{
JObject jobject = data;
string filterRoot = dataFilter.FilterRoot; // the node we want to apply the filter at e.g. "Location.Rows";
string tokenNameToCheck = dataFilter.PropertyNameToFilterOn; // the name of property we want to filter on e.g. "BedId";
string filterType = dataFilter.FilterType; // the type of filter e.g. "Exclude" or "Include";
List<string> filterItems = dataFilter.FilterItemValues.Split(',').ToList(); // new List<string> { "K2", "K3" };
List<JToken> matchedItems = new List<JToken>(); // will contain a list of items that match our filter
// get the collection we want to apply the filter too
var rows = jobject.SelectToken(filterRoot);
// find and make a collection of the items that match our filter
foreach (var item in rows)
{
var value = (string)item.SelectToken(tokenNameToCheck);
if (filterItems.Contains(value))
{
matchedItems.Add(item);
}
}
// remove any of our matched items
if (filterType == "Exclude")
{
foreach (var item in matchedItems)
{
item.Remove();
}
}
// remove anything not in our matched items (i.e. only keep matches)
if (filterType == "Include")
{
var nonMatches = rows.Where(i => !matchedItems.Contains(i)).ToList();
foreach (var item in nonMatches)
{
item.Remove();
}
}
return jobject;
}
The custom comparer that does the actual sorting:
/// <summary>
/// compares two jobjects based on a list of sorts (containing a field name and sort direction) passed into the constructor
/// </summary>
public class JObjectSortComparer : IComparer<JObject>
{
private List<DisplayGroupDataSort> requiredSorts;
public JObjectSortComparer(List<DisplayGroupDataSort> sorts)
{
requiredSorts = sorts;
}
public int Compare(JObject a, JObject b)
{
return DoCompare(a, b, 0);
}
private int DoCompare(JObject a, JObject b, int depth)
{
var fieldName = requiredSorts[depth].Field;
var compareResult = string.Compare((string)a.SelectToken(fieldName), (string)b.SelectToken(fieldName));
if (requiredSorts[depth].Direction.ToLower() == "desc")
{
compareResult = compareResult * -1;
}
if (compareResult == 0 && depth < requiredSorts.Count - 1)
{
return DoCompare(a, b, depth + 1);
}
return compareResult;
}
}
No comments:
Post a Comment