Skip to content
This repository was archived by the owner on Jul 6, 2020. It is now read-only.

Commit

Permalink
Added nullable types support.
Browse files Browse the repository at this point in the history
  • Loading branch information
VahidN committed Dec 22, 2015
1 parent d6d4a32 commit 0487229
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 67 deletions.
182 changes: 119 additions & 63 deletions JqGridHelper/JqGridHelper/DynamicSearch/JqGridSearch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,65 +26,62 @@ namespace JqGridHelper.DynamicSearch
/// </summary>
public class JqGridSearch
{
/// <summary>
/// هر اپراتوری را به هر نوع داده‌ای نمی‌توان اعمال کرد
/// </summary>
private static readonly Dictionary<string, string> _validOperators =
new Dictionary<string, string>
{
{ "Object"   ,  "" },
{ "Boolean"  ,  "eq:ne:" },
{ "Char"     ,  "" },
{ "String"   ,  "eq:ne:lt:le:gt:ge:bw:bn:cn:nc:" },
{ "SByte"    ,  "" },
{ "Byte"     ,  "eq:ne:lt:le:gt:ge:" },
{ "Int16"    ,  "eq:ne:lt:le:gt:ge:" },
{ "UInt16"   ,  "" },
{ "Int32"    ,  "eq:ne:lt:le:gt:ge:" },
{ "UInt32"   ,  "" },
{ "Int64"    ,  "eq:ne:lt:le:gt:ge:" },
{ "UInt64"   ,  "" },
{ "Decimal"  ,  "eq:ne:lt:le:gt:ge:" },
{ "Single"   ,  "eq:ne:lt:le:gt:ge:" },
{ "Double"   ,  "eq:ne:lt:le:gt:ge:" },
{ "DateTime" ,  "eq:ne:lt:le:gt:ge:" },
{ "TimeSpan" ,  "" },
{ "Guid"     ,  "eq:ne:" }
};

private static readonly Dictionary<string, string> _whereOperation =
new Dictionary<string, string>
{
{"in" , " {0} = @{1} "},//is in
{"eq" , " {0} = @{1} "},
{"ni" , " {0} != @{1} "},//is not in
{"ne" , " {0} != @{1} "},
{"lt" , " {0} < @{1} "},
{"le" , " {0} <= @{1} "},
{"gt" , " {0} > @{1} "},
{"ge" , " {0} >= @{1} "},
{"bw" , " {0}.StartsWith(@{1}) "},//begins with
{"bn" , " !{0}.StartsWith(@{1}) "},//does not begin with
{"ew" , " {0}.EndsWith(@{1}) "},//ends with
{"en" , " !{0}.EndsWith(@{1}) "},//does not end with
{"cn" , " {0}.Contains(@{1}) "},//contains
{"nc" , " !{0}.Contains(@{1}) "}//does not contain
};

private readonly JqGridRequest _request;
private readonly NameValueCollection _form;
private readonly DateTimeType _dateTimeType;
private readonly NameValueCollection _form;
private readonly JqGridRequest _request;
private int _parameterIndex;

public JqGridSearch(JqGridRequest request, NameValueCollection form, DateTimeType dateTimeType)
{
_request = request;
_form = form;
_dateTimeType = dateTimeType;
}

private static readonly Dictionary<string, string> _whereOperation =
new Dictionary<string, string>
                {
        {"in" , " {0} = @{1} "},//is in
{"eq" , " {0} = @{1} "},
{"ni" , " {0} != @{1} "},//is not in
{"ne" , " {0} != @{1} "},
{"lt" , " {0} < @{1} "},
{"le" , " {0} <= @{1} "},
{"gt" , " {0} > @{1} "},
{"ge" , " {0} >= @{1} "},
{"bw" , " {0}.StartsWith(@{1}) "},//begins with
{"bn" , " !{0}.StartsWith(@{1}) "},//does not begin with
{"ew" , " {0}.EndsWith(@{1}) "},//ends with
{"en" , " !{0}.EndsWith(@{1}) "},//does not end with
{"cn" , " {0}.Contains(@{1}) "},//contains
{"nc" , " !{0}.Contains(@{1}) "}//does not contain
                };

/// <summary>
/// هر اپراتوری را به هر نوع داده‌ای نمی‌توان اعمال کرد
/// </summary>
private static readonly Dictionary<string, string> _validOperators =
new Dictionary<string, string>
                {
                    { "Object"   ,  "" },
                    { "Boolean"  ,  "eq:ne:" },
                    { "Char"     ,  "" },
                    { "String"   ,  "eq:ne:lt:le:gt:ge:bw:bn:cn:nc:" },
                    { "SByte"    ,  "" },
                    { "Byte"     ,  "eq:ne:lt:le:gt:ge:" },
                    { "Int16"    ,  "eq:ne:lt:le:gt:ge:" },
                    { "UInt16"   ,  "" },
                     { "Int32"    ,  "eq:ne:lt:le:gt:ge:" },
                     { "UInt32"   ,  "" },
                    { "Int64"    ,  "eq:ne:lt:le:gt:ge:" },
                    { "UInt64"   ,  "" },
                    { "Decimal"  ,  "eq:ne:lt:le:gt:ge:" },
                    { "Single"   ,  "eq:ne:lt:le:gt:ge:" },
                    { "Double"   ,  "eq:ne:lt:le:gt:ge:" },
                    { "DateTime" ,  "eq:ne:lt:le:gt:ge:" },
                    { "TimeSpan" ,  "" },
                    { "Guid"     ,  "eq:ne:" }
                };

private int _parameterIndex;

public IQueryable<T> ApplyFilter<T>(IQueryable<T> query)
{
if (!_request._search)
Expand All @@ -101,37 +98,69 @@ public IQueryable<T> ApplyFilter<T>(IQueryable<T> query)
manageMultiFieldSearch(query) : manageToolbarSearch(query);
}

private Tuple<string, object> getPredicate<T>(string searchField, string searchOper, string searchValue)

private static bool isNullable(Type type)
{
if (string.IsNullOrWhiteSpace(searchValue))
return null;
return Nullable.GetUnderlyingType(type) != null;
}

private object getDefaultValue(Type t)
{
return t.IsValueType ? Activator.CreateInstance(t) : null;
}

private Tuple<string, object> getPredicate<T>(string searchField, string searchOper, string searchValue)
{
var type = typeof(T).FindFieldType(searchField);
if (type == null)
throw new InvalidOperationException(string.Format("{0} is not defined.", searchField));
{
return null;
}

if (string.IsNullOrWhiteSpace(searchValue))
{
var defaultValue = getDefaultValue(type);
searchValue = defaultValue == null ? "null" : defaultValue.ToString();
}

var searchOperator = getSearchOperator(searchOper, searchField, type, searchValue);

if (isNullable(type))
{
type = Nullable.GetUnderlyingType(type);
}

if (!_validOperators[type.Name].Contains(string.Format("{0}:", searchOper)))
{
// این اپراتور روی نوع داده‌ای جاری کار نمی‌کند
throw new NotImplementedException(string.Format("{0} & {1} is not supported.", type.Name, searchOper));
}

if (type == typeof(decimal))
{
if (searchValue == "null")
{
return new Tuple<string, object>(searchOperator, null);
}

decimal value;
if (decimal.TryParse(searchValue, NumberStyles.Any, Thread.CurrentThread.CurrentCulture, out value))
{
return new Tuple<string, object>(getSearchOperator(searchOper, searchField, type), value);
return new Tuple<string, object>(searchOperator, value);
}
}

if (type == typeof(DateTime))
{
if (searchValue == "null")
{
return new Tuple<string, object>(searchOperator, null);
}

DateTime dateTime;
switch (_dateTimeType)
{
case DateTimeType.Gregorian:
dateTime = DateTime.Parse(searchValue);
dateTime = DateTime.Parse(searchValue, CultureInfo.InvariantCulture);
break;
case DateTimeType.Persian:
var parts = searchValue.Split('/'); //ex. 1391/1/19
Expand All @@ -144,27 +173,42 @@ private Tuple<string, object> getPredicate<T>(string searchField, string searchO
default:
throw new NotSupportedException(string.Format("{0} is not supported.", _dateTimeType));
}
return new Tuple<string, object>(getSearchOperator(searchOper, searchField, type), dateTime);
return new Tuple<string, object>(searchOperator, dateTime);
}

if (type == typeof(Guid))
{
var guid = new Guid(searchValue);
return new Tuple<string, object>(getSearchOperator(searchOper, searchField, type), guid);
var guid = searchValue == "null" ? (Guid?)null : new Guid(searchValue);
return new Tuple<string, object>(searchOperator, guid);
}

var resultValue = Convert.ChangeType(searchValue, type);
return new Tuple<string, object>(getSearchOperator(searchOper, searchField, type), resultValue);
return new Tuple<string, object>(searchOperator, resultValue);
}

private string getSearchOperator(string ruleSearchOperator, string searchField, Type type)
private string getSearchOperator(string ruleSearchOperator, string searchField, Type type, string searchValue)
{
string whereOperation;
if (!_whereOperation.TryGetValue(ruleSearchOperator, out whereOperation))
{
throw new NotSupportedException(string.Format("{0} is not supported.", ruleSearchOperator));
}

if (isNullable(type) && (searchValue == "null"))
{
switch (ruleSearchOperator)
{
case "eq":
whereOperation = " !{0}.HasValue ";
break;
case "ne":
whereOperation = " {0}.HasValue ";
break;
default:
throw new NotSupportedException(string.Format("{0} is not supported.", ruleSearchOperator));
}
}

if (type == typeof(DateTime))
{
switch (ruleSearchOperator)
Expand Down Expand Up @@ -239,11 +283,23 @@ private IQueryable<T> manageToolbarSearch<T>(IQueryable<T> query)
}
}

if (string.IsNullOrWhiteSpace(filterExpression))
{
//{_search=true&nd=1450767916380&rows=10&page=1&sidx=Id&sord=asc&searchField=Code&searchString=&searchOper=eq&filters=}
var predicate = getPredicate<T>(_form["searchField"], _form["searchOper"], _form["searchString"]);
if (predicate != null)
{
valuesList.Add(predicate.Item2);
filterExpression = string.Format("{0}{1} And ", filterExpression, predicate.Item1);
}
}

if (string.IsNullOrWhiteSpace(filterExpression))
return query;

filterExpression = filterExpression.Remove(filterExpression.Length - 5);
query = query.Where(filterExpression, valuesList.ToArray());
var args = valuesList.ToArray();
query = query.Where(filterExpression, args);
return query;
}
}
Expand Down
4 changes: 2 additions & 2 deletions jqGrid03/jqGrid03/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public ActionResult GetProducts(JqGridRequest request)
var totalPages = (int)Math.Ceiling(totalRecords / (float)pageSize);

var productsQuery = list.AsQueryable();

//System.Collections.Generic.List`1[jqGrid03.Models.Product].Where(Param_0 => Param_0.Code.Value.ToString().Equals(null))}
productsQuery = new JqGridSearch(request, this.Request.Form, DateTimeType.Persian).ApplyFilter(productsQuery);
var productsList = productsQuery.OrderBy(request.sidx + " " + request.sord)
.Skip(pageIndex * pageSize)
Expand All @@ -50,7 +50,7 @@ public ActionResult GetProducts(JqGridRequest request)
product.Supplier.CompanyName,
product.Category.Name,
product.Price.ToString(CultureInfo.InvariantCulture),
product.Code.ToString("D")
product.Code.HasValue? product.Code.Value.ToString("D") : string.Empty
}
})).ToArray()
};
Expand Down
2 changes: 1 addition & 1 deletion jqGrid03/jqGrid03/Models/Product.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class Product
public decimal Price { set; get; }
public Supplier Supplier { set; get; }
public Category Category { set; get; }
public Guid Code { set; get; }
public Guid? Code { set; get; }
}

public class Category
Expand Down
2 changes: 1 addition & 1 deletion jqGrid03/jqGrid03/Models/ProductDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private static IList<Product> createProductsDataSource()
Id = i + 1,
Name = "نام " + (i + 1),
Price = i * 1000,
Code = Guid.NewGuid(),
Code = (i % 2 == 0) ? Guid.NewGuid() : (Guid?)null,
Supplier = new Supplier
{
Id = i + 1,
Expand Down

0 comments on commit 0487229

Please sign in to comment.