|
@@ -64,15 +64,20 @@ namespace Vit.Linq.QueryBuilder
|
|
|
}
|
|
|
|
|
|
|
|
|
+ public virtual ECondition GetCondition(IFilterRule filter)
|
|
|
+ {
|
|
|
+ return filter.condition?.ToLower() == "or" ? ECondition.or : ECondition.and;
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
|
- public ECondition GetCondition(IFilterRule filter)
|
|
|
+ protected virtual Expression GetLeftValueExpression(IFilterRule rule, ParameterExpression valueExpression)
|
|
|
{
|
|
|
- return filter.condition?.ToLower() == "or" ? ECondition.or : ECondition.and;
|
|
|
+ return rule.GetLeftValueExpression(valueExpression);
|
|
|
}
|
|
|
|
|
|
- public string GetOperator(IFilterRule filter)
|
|
|
+
|
|
|
+ public virtual string GetOperator(IFilterRule filter)
|
|
|
{
|
|
|
var operate = filter.@operator ?? "";
|
|
|
if (operatorIsIgnoreCase) operate = operate.ToLower();
|
|
@@ -80,7 +85,10 @@ namespace Vit.Linq.QueryBuilder
|
|
|
return operate;
|
|
|
}
|
|
|
|
|
|
- public Func<object, IFilterRule, Type, object> GetRuleValue;
|
|
|
+
|
|
|
+ #region GetRightValueExpression
|
|
|
+
|
|
|
+ public Func<object, IFilterRule, Type, object> GetRuleValue { get; set; }
|
|
|
protected virtual object GetRulePrimitiveValue(object value, IFilterRule rule, Type fieldType)
|
|
|
{
|
|
|
if (GetRuleValue != null) return GetRuleValue(value, rule, fieldType);
|
|
@@ -88,6 +96,74 @@ namespace Vit.Linq.QueryBuilder
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+ protected virtual Expression GetRightValueExpression(IFilterRule rule, ParameterExpression parameter, Type valueType)
|
|
|
+ {
|
|
|
+ object rightValue = rule.value;
|
|
|
+
|
|
|
+ // typeof(IEnumerable).IsAssignableFrom(valueType)
|
|
|
+ if (valueType.IsGenericType && typeof(IEnumerable<>).IsAssignableFrom(valueType.GetGenericTypeDefinition()))
|
|
|
+ {
|
|
|
+ // constant List
|
|
|
+ object value = null;
|
|
|
+ if (rule.value != null)
|
|
|
+ {
|
|
|
+ //value = Vit.Core.Module.Serialization.Json.Deserialize(Vit.Core.Module.Serialization.Json.Serialize(rule.value), valueType);
|
|
|
+ var leftFieldType = valueType.GetGenericArguments()[0];
|
|
|
+ value = ConvertToList(rule.value, rule, leftFieldType);
|
|
|
+ }
|
|
|
+ rightValue = value;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // constant value
|
|
|
+ object value = GetRulePrimitiveValue(rule.value, rule, valueType);
|
|
|
+ if (value != null)
|
|
|
+ {
|
|
|
+ Type type = Nullable.GetUnderlyingType(valueType) ?? valueType;
|
|
|
+ value = Convert.ChangeType(value, type);
|
|
|
+ }
|
|
|
+ rightValue = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ Expression<Func<object>> valueLamba = () => rightValue;
|
|
|
+ return Expression.Convert(valueLamba.Body, valueType);
|
|
|
+ }
|
|
|
+
|
|
|
+ #region ConvertToList
|
|
|
+ internal object ConvertToList(object value, IFilterRule rule, Type fieldType)
|
|
|
+ {
|
|
|
+ if (value is string str)
|
|
|
+ {
|
|
|
+ var itemValue = GetRulePrimitiveValue(str, rule, fieldType);
|
|
|
+ if (itemValue is IEnumerable)
|
|
|
+ return itemValue;
|
|
|
+ }
|
|
|
+ else if (value is IEnumerable values)
|
|
|
+ {
|
|
|
+ var methodInfo = typeof(QueryBuilderService).GetMethod("ConvertToListByType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).MakeGenericMethod(fieldType);
|
|
|
+ return methodInfo.Invoke(this, new object[] { values, rule });
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ internal List<T> ConvertToListByType<T>(IEnumerable values, IFilterRule rule)
|
|
|
+ {
|
|
|
+ Type fieldType = typeof(T);
|
|
|
+ var list = new List<T>();
|
|
|
+ foreach (var item in values)
|
|
|
+ {
|
|
|
+ var itemValue = GetRulePrimitiveValue(item, rule, fieldType);
|
|
|
+ T value = (T)Convert.ChangeType(itemValue, fieldType);
|
|
|
+ list.Add(value);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+
|
|
|
Expression ConvertToExpression(IFilterRule rule, ParameterExpression parameter)
|
|
|
{
|
|
|
if (rule == null) return null;
|
|
@@ -99,17 +175,16 @@ namespace Vit.Linq.QueryBuilder
|
|
|
}
|
|
|
|
|
|
// #2 simple rule
|
|
|
- if (string.IsNullOrWhiteSpace(rule.field))
|
|
|
+ if (string.IsNullOrWhiteSpace(rule.@operator))
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- MemberExpression memberExp = LinqHelp.GetFieldMemberExpression(parameter, rule.field);
|
|
|
+ Expression leftValueExpression = GetLeftValueExpression(rule, parameter);
|
|
|
+ Type leftFieldType = leftValueExpression.Type;
|
|
|
|
|
|
#region Get Expression
|
|
|
|
|
|
- Type fieldType = memberExp.Type;
|
|
|
-
|
|
|
var Operator = GetOperator(rule);
|
|
|
var cmpType = operatorIsIgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
|
|
|
|
|
@@ -130,29 +205,29 @@ namespace Vit.Linq.QueryBuilder
|
|
|
#region ##2 number
|
|
|
if (FilterRuleOperator.Equal.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- return Expression.Equal(memberExp, ConvertValueExp());
|
|
|
+ return Expression.Equal(leftValueExpression, GetRightValueExpression());
|
|
|
}
|
|
|
if (FilterRuleOperator.NotEqual.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- return Expression.NotEqual(memberExp, ConvertValueExp());
|
|
|
+ return Expression.NotEqual(leftValueExpression, GetRightValueExpression());
|
|
|
}
|
|
|
|
|
|
if (FilterRuleOperator.GreaterThan.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- return Expression.GreaterThan(memberExp, ConvertValueExp());
|
|
|
+ return Expression.GreaterThan(leftValueExpression, GetRightValueExpression());
|
|
|
}
|
|
|
if (FilterRuleOperator.GreaterThanOrEqual.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- return Expression.GreaterThanOrEqual(memberExp, ConvertValueExp());
|
|
|
+ return Expression.GreaterThanOrEqual(leftValueExpression, GetRightValueExpression());
|
|
|
}
|
|
|
if (FilterRuleOperator.LessThan.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- return Expression.LessThan(memberExp, ConvertValueExp());
|
|
|
+ return Expression.LessThan(leftValueExpression, GetRightValueExpression());
|
|
|
|
|
|
}
|
|
|
if (FilterRuleOperator.LessThanOrEqual.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- return Expression.LessThanOrEqual(memberExp, ConvertValueExp());
|
|
|
+ return Expression.LessThanOrEqual(leftValueExpression, GetRightValueExpression());
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
@@ -172,40 +247,40 @@ namespace Vit.Linq.QueryBuilder
|
|
|
#region ##4 string
|
|
|
if (FilterRuleOperator.Contains.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- var nullCheck = Expression.Call(typeof(string), "IsNullOrEmpty", null, memberExp);
|
|
|
- var contains = Expression.Call(memberExp, "Contains", null, ConvertValueExp());
|
|
|
+ var nullCheck = Expression.Call(typeof(string), "IsNullOrEmpty", null, leftValueExpression);
|
|
|
+ var contains = Expression.Call(leftValueExpression, "Contains", null, GetRightValueExpression());
|
|
|
|
|
|
return Expression.AndAlso(Expression.Not(nullCheck), contains);
|
|
|
|
|
|
}
|
|
|
if (FilterRuleOperator.NotContains.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- var nullCheck = Expression.Call(typeof(string), "IsNullOrEmpty", null, memberExp);
|
|
|
- var contains = Expression.Call(memberExp, "Contains", null, ConvertValueExp());
|
|
|
+ var nullCheck = Expression.Call(typeof(string), "IsNullOrEmpty", null, leftValueExpression);
|
|
|
+ var contains = Expression.Call(leftValueExpression, "Contains", null, GetRightValueExpression());
|
|
|
|
|
|
return Expression.OrElse(nullCheck, Expression.Not(contains));
|
|
|
}
|
|
|
if (FilterRuleOperator.StartsWith.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, memberExp));
|
|
|
- var startsWith = Expression.Call(memberExp, "StartsWith", null, ConvertValueExp());
|
|
|
+ var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, leftValueExpression));
|
|
|
+ var startsWith = Expression.Call(leftValueExpression, "StartsWith", null, GetRightValueExpression());
|
|
|
|
|
|
return Expression.AndAlso(nullCheck, startsWith);
|
|
|
}
|
|
|
|
|
|
if (FilterRuleOperator.EndsWith.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, memberExp));
|
|
|
- var endsWith = Expression.Call(memberExp, "EndsWith", null, ConvertValueExp());
|
|
|
+ var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, leftValueExpression));
|
|
|
+ var endsWith = Expression.Call(leftValueExpression, "EndsWith", null, GetRightValueExpression());
|
|
|
return Expression.AndAlso(nullCheck, endsWith);
|
|
|
}
|
|
|
if (FilterRuleOperator.IsNullOrEmpty.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- return Expression.Call(typeof(string), "IsNullOrEmpty", null, memberExp);
|
|
|
+ return Expression.Call(typeof(string), "IsNullOrEmpty", null, leftValueExpression);
|
|
|
}
|
|
|
if (FilterRuleOperator.IsNotNullOrEmpty.Equals(Operator, cmpType))
|
|
|
{
|
|
|
- return Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, memberExp));
|
|
|
+ return Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, leftValueExpression));
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
@@ -216,29 +291,20 @@ namespace Vit.Linq.QueryBuilder
|
|
|
return null;
|
|
|
|
|
|
|
|
|
- #region Method ConvertValueExp
|
|
|
- UnaryExpression ConvertValueExp()
|
|
|
+ #region inner Method
|
|
|
+ Expression GetRightValueExpression()
|
|
|
{
|
|
|
- object value = GetRulePrimitiveValue(rule.value,rule,fieldType);
|
|
|
- if (value != null)
|
|
|
- {
|
|
|
- Type valueType = Nullable.GetUnderlyingType(fieldType) ?? fieldType;
|
|
|
- value = Convert.ChangeType(value, valueType);
|
|
|
- }
|
|
|
-
|
|
|
- Expression<Func<object>> valueLamba = () => value;
|
|
|
- return Expression.Convert(valueLamba.Body, fieldType);
|
|
|
+ return this.GetRightValueExpression(rule, parameter, leftFieldType);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
Expression IsNull()
|
|
|
{
|
|
|
- var isNullable = !fieldType.IsValueType || Nullable.GetUnderlyingType(fieldType) != null;
|
|
|
+ var isNullable = !leftFieldType.IsValueType || Nullable.GetUnderlyingType(leftFieldType) != null;
|
|
|
|
|
|
if (isNullable)
|
|
|
{
|
|
|
- var nullValue = Expression.Constant(null, fieldType);
|
|
|
- return Expression.Equal(memberExp, nullValue);
|
|
|
+ var nullValue = Expression.Constant(null, leftFieldType);
|
|
|
+ return Expression.Equal(leftValueExpression, nullValue);
|
|
|
}
|
|
|
return Expression.Constant(false, typeof(bool));
|
|
|
}
|
|
@@ -246,20 +312,10 @@ namespace Vit.Linq.QueryBuilder
|
|
|
Expression In()
|
|
|
{
|
|
|
Expression arrayExp = null;
|
|
|
- #region build arrayExp
|
|
|
- {
|
|
|
- Type valueType = typeof(IEnumerable<>).MakeGenericType(fieldType);
|
|
|
- object value = null;
|
|
|
- if (rule.value != null)
|
|
|
- {
|
|
|
- //value = Vit.Core.Module.Serialization.Json.Deserialize(Vit.Core.Module.Serialization.Json.Serialize(rule.value), valueType);
|
|
|
- value = ConvertToList(rule.value, rule, fieldType);
|
|
|
- }
|
|
|
- Expression<Func<object>> valueLamba = () => value;
|
|
|
- arrayExp = Expression.Convert(valueLamba.Body, valueType);
|
|
|
- }
|
|
|
- #endregion
|
|
|
- var inCheck = Expression.Call(typeof(System.Linq.Enumerable), "Contains", new[] { fieldType }, arrayExp, memberExp);
|
|
|
+ Type valueType = typeof(IEnumerable<>).MakeGenericType(leftFieldType);
|
|
|
+ arrayExp = this.GetRightValueExpression(rule, parameter, valueType);
|
|
|
+
|
|
|
+ var inCheck = Expression.Call(typeof(System.Linq.Enumerable), "Contains", new[] { leftFieldType }, arrayExp, leftValueExpression);
|
|
|
return inCheck;
|
|
|
}
|
|
|
#endregion
|
|
@@ -303,34 +359,6 @@ namespace Vit.Linq.QueryBuilder
|
|
|
|
|
|
}
|
|
|
|
|
|
- #region ConvertToList
|
|
|
- internal object ConvertToList(object value,IFilterRule rule, Type fieldType)
|
|
|
- {
|
|
|
- if (value is string str)
|
|
|
- {
|
|
|
- var itemValue = GetRulePrimitiveValue(str, rule, fieldType);
|
|
|
- if (itemValue is IEnumerable)
|
|
|
- return itemValue;
|
|
|
- }
|
|
|
- else if (value is IEnumerable values)
|
|
|
- {
|
|
|
- var methodInfo = typeof(QueryBuilderService).GetMethod("ConvertToListByType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).MakeGenericMethod(fieldType);
|
|
|
- return methodInfo.Invoke(this, new object[] { values , rule });
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
- internal List<T> ConvertToListByType<T>(IEnumerable values, IFilterRule rule)
|
|
|
- {
|
|
|
- Type fieldType = typeof(T);
|
|
|
- var list = new List<T>();
|
|
|
- foreach (var item in values)
|
|
|
- {
|
|
|
- var itemValue = GetRulePrimitiveValue(item, rule, fieldType);
|
|
|
- T value = (T)Convert.ChangeType(itemValue, fieldType);
|
|
|
- list.Add(value);
|
|
|
- }
|
|
|
- return list;
|
|
|
- }
|
|
|
- #endregion
|
|
|
+
|
|
|
}
|
|
|
}
|