diff options
author | Jeroen Walter <jeroen@enormkansloos.nl> | 2012-09-02 20:21:11 +0200 |
---|---|---|
committer | Jeroen Walter <jeroen@enormkansloos.nl> | 2012-09-02 20:21:11 +0200 |
commit | ad80e42e5a9069bd09d68707a1ff548e99f7431e (patch) | |
tree | c2dafc6725e5a7ae088d05566bffa7ad8d72fc33 /ComicRackWebViewer/Modules/BCRModule.cs | |
parent | bfd94e40290f2cb5b91c80adadcc8b30f42d8ad3 (diff) | |
download | ComicRackWeb-ad80e42e5a9069bd09d68707a1ff548e99f7431e.zip ComicRackWeb-ad80e42e5a9069bd09d68707a1ff548e99f7431e.tar.gz ComicRackWeb-ad80e42e5a9069bd09d68707a1ff548e99f7431e.tar.bz2 |
- added natural sort algorithm
Diffstat (limited to 'ComicRackWebViewer/Modules/BCRModule.cs')
-rw-r--r-- | ComicRackWebViewer/Modules/BCRModule.cs | 158 |
1 files changed, 152 insertions, 6 deletions
diff --git a/ComicRackWebViewer/Modules/BCRModule.cs b/ComicRackWebViewer/Modules/BCRModule.cs index 990b851..7fb74ce 100644 --- a/ComicRackWebViewer/Modules/BCRModule.cs +++ b/ComicRackWebViewer/Modules/BCRModule.cs @@ -18,12 +18,102 @@ using Nancy; using Nancy.ModelBinding; using Nancy.Responses; using ComicRackWebViewer; +using System.Text.RegularExpressions; using Linq2Rest.Parser; namespace BCR { + public class NaturalSortComparer<T> : IComparer<string>, IDisposable + { + private bool isAscending; + + public NaturalSortComparer(bool inAscendingOrder = true) + { + this.isAscending = inAscendingOrder; + } + + #region IComparer<string> Members + + public int Compare(string x, string y) + { + throw new NotImplementedException(); + } + + #endregion + + #region IComparer<string> Members + + int IComparer<string>.Compare(string x, string y) + { + if (x == y) + return 0; + + string[] x1, y1; + + if (!table.TryGetValue(x, out x1)) + { + x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)"); + table.Add(x, x1); + } + + if (!table.TryGetValue(y, out y1)) + { + y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)"); + table.Add(y, y1); + } + + int returnVal; + + for (int i = 0; i < x1.Length && i < y1.Length; i++) + { + if (x1[i] != y1[i]) + { + returnVal = PartCompare(x1[i], y1[i]); + return isAscending ? returnVal : -returnVal; + } + } + + if (y1.Length > x1.Length) + { + returnVal = 1; + } + else if (x1.Length > y1.Length) + { + returnVal = -1; + } + else + { + returnVal = 0; + } + + return isAscending ? returnVal : -returnVal; + } + + private static int PartCompare(string left, string right) + { + int x, y; + if (!int.TryParse(left, out x)) + return left.CompareTo(right); + + if (!int.TryParse(right, out y)) + return left.CompareTo(right); + + return x.CompareTo(y); + } + + #endregion + + private Dictionary<string, string[]> table = new Dictionary<string, string[]>(); + + public void Dispose() + { + table.Clear(); + table = null; + } + } + public static class ODataExtensions { private const string ODATA_URI_KEY = "OData_Uri"; @@ -57,20 +147,44 @@ namespace BCR } return nv; } + + public static string GetReflectedPropertyValue(this object subject, string field) + { + object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null); + return reflectedValue != null ? reflectedValue.ToString() : ""; + } + public static IEnumerable<object> ApplyODataUriFilter<T>(this NancyContext context, IEnumerable<T> modelItems, ref int totalCount) { var nv = MyParseUriOptions(context); - NameValueCollection selectNV = new NameValueCollection(); + // $select is broken somehow....remove it for now + //NameValueCollection selectNV = new NameValueCollection(); //selectNV.Add("$select", nv.Get("$select")); nv.Remove("$select"); + NameValueCollection pagingNV = new NameValueCollection(); // We want the total count of the query before limiting the result set with $top and $skip - selectNV.Add("$skip", nv.Get("$skip")); - nv.Remove("$skip"); - selectNV.Add("$top", nv.Get("$top")); - nv.Remove("$top"); + if (null != nv.Get("$skip")) + { + pagingNV.Add("$skip", nv.Get("$skip")); + nv.Remove("$skip"); + } + + if (null != nv.Get("$top")) + { + pagingNV.Add("$top", nv.Get("$top")); + nv.Remove("$top"); + } + + // perform sorting ourselves, because linq2rest doesn't allow custom comparers. + NameValueCollection sortNV = new NameValueCollection(); + if (null != nv.Get("$orderby")) + { + sortNV.Add("$orderby", nv.Get("$orderby")); + nv.Remove("$orderby"); + } // Now do a query that returns all records var parser = new ParameterParser<T>(); @@ -78,9 +192,41 @@ namespace BCR var objects = filter.Filter(modelItems); totalCount = objects.Count(); + // Now sort + // Right now, only a single sort term is supported. + if (null != sortNV.Get("$orderby")) + { + char[] delimiterChars = {','}; + string[] orderby = sortNV.Get("$orderby").Split(delimiterChars); + char[] delimiterSpace = {' '}; + string[] terms = orderby[0].Split(delimiterSpace); + bool ascending = true; + if (terms.Count() == 2) + ascending = terms[1] != "desc"; + + if (orderby.Count() == 1) + { + objects = objects.OrderBy(item => item.GetReflectedPropertyValue(terms[0]), new NaturalSortComparer<string>(ascending)); + } + else + if (orderby.Count() > 1) + { + // get the second orderby + string[] terms2 = orderby[1].Split(delimiterSpace); + bool ascending2 = true; + if (terms2.Count() == 2) + ascending2 = terms2[1] != "desc"; + + objects = objects.OrderBy(item => item.GetReflectedPropertyValue(terms[0]), new NaturalSortComparer<string>(ascending)) + .ThenBy(item => item.GetReflectedPropertyValue(terms2[0]), new NaturalSortComparer<string>(ascending2)); + } + + } + + // Now limit the resultset var parser2 = new ParameterParser<T>(); - var filter2 = parser2.Parse(selectNV); + var filter2 = parser2.Parse(pagingNV); var objects2 = filter2.Filter(objects.Cast<T>()); return objects2; } |