summaryrefslogtreecommitdiffstats
path: root/ComicRackWebViewer/Modules/BCRModule.cs
diff options
context:
space:
mode:
authorJeroen Walter <jeroen@enormkansloos.nl>2012-09-02 20:21:11 +0200
committerJeroen Walter <jeroen@enormkansloos.nl>2012-09-02 20:21:11 +0200
commitad80e42e5a9069bd09d68707a1ff548e99f7431e (patch)
treec2dafc6725e5a7ae088d05566bffa7ad8d72fc33 /ComicRackWebViewer/Modules/BCRModule.cs
parentbfd94e40290f2cb5b91c80adadcc8b30f42d8ad3 (diff)
downloadComicRackWeb-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.cs158
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;
}