Explorar o código

move filter value getter logic to FilterRule class
#gogs14_2024-01-19_SupportMethodLikeCount

lith hai 1 ano
pai
achega
65d6626e88

+ 3 - 20
src/Vit.Linq.NewtonsoftJson/FilterRule_Newtonsoft.cs

@@ -11,32 +11,15 @@ namespace Vit.Linq.QueryBuilder.NewtonsoftJson
     /// This class is used to define a hierarchical filter for a given collection. This type can be serialized/deserialized by JSON.NET without needing to modify the data structure from QueryBuilder.
     /// </summary>
     [ExcludeFromCodeCoverage]
-    public class FilterRule_Newtonsoft : IFilterRule
+    public class FilterRule_Newtonsoft : FilterRuleBase<FilterRule_Newtonsoft>
     {
-        /// <summary>
-        /// condition - acceptable values are "and" and "or".
-        /// </summary>
-        public string condition { get; set; }
-
-
-        public string field { get; set; }
-
-
-        public string @operator { get; set; }
-
-        /// <summary>
-        ///  nested filter rules.
-        /// </summary>
-        public List<FilterRule_Newtonsoft> rules { get; set; }
-
-
         /// <summary>
         /// Gets or sets the value of the filter.
         /// </summary>
         /// <value>
         /// The value.
         /// </value>
-        public object value
+        public override object value
         {
             get
             {
@@ -51,7 +34,7 @@ namespace Vit.Linq.QueryBuilder.NewtonsoftJson
 
         private object _value;
 
-        IEnumerable<IFilterRule> IFilterRule.rules => rules;
+ 
 
 
         public static FilterRule_Newtonsoft FromString(string filter)

+ 7 - 26
src/Vit.Linq.SystemTextJson/FilterRule_SystemTextJson.cs

@@ -11,32 +11,15 @@ namespace Vit.Linq.QueryBuilder.SystemTextJson
     /// This class is used to define a hierarchical filter for a given collection. This type can be serialized/deserialized by JSON.NET without needing to modify the data structure from QueryBuilder.
     /// </summary>
     [ExcludeFromCodeCoverage]
-    public class FilterRule_SystemTextJson : IFilterRule
+    public class FilterRule_SystemTextJson : FilterRuleBase<FilterRule_SystemTextJson>
     {
-        /// <summary>
-        /// condition - acceptable values are "and" and "or".
-        /// </summary>
-        public string condition { get; set; }
-
-
-        public string field { get; set; }
-
-
-        public string @operator { get; set; }
-
-        /// <summary>
-        ///  nested filter rules.
-        /// </summary>
-        public List<FilterRule_SystemTextJson> rules { get; set; }
-
-
         /// <summary>
         /// Gets or sets the value of the filter.
         /// </summary>
         /// <value>
         /// The value.
         /// </value>
-        public object value
+        public override object value
         {
             get
             {
@@ -51,26 +34,24 @@ namespace Vit.Linq.QueryBuilder.SystemTextJson
 
         private object _value;
 
-        IEnumerable<IFilterRule> IFilterRule.rules => rules;
-
 
         public static FilterRule_SystemTextJson FromString(string filter)
         {
-            return JsonSerializer.Deserialize<FilterRule_SystemTextJson>(filter, options); 
+            return JsonSerializer.Deserialize<FilterRule_SystemTextJson>(filter, options);
         }
 
         static readonly JsonSerializerOptions options = GetDefaultOptions();
 
 
-        public static JsonSerializerOptions GetDefaultOptions(  )
+        public static JsonSerializerOptions GetDefaultOptions()
         {
-          var options=  new JsonSerializerOptions
+            var options = new JsonSerializerOptions
             {
                 // avoid transfer chinese character, for example {"title":"\u4ee3\u7801\u6539\u53d8\u4e16\u754c"}
                 Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),
                 IncludeFields = true,
                 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
-            }; 
+            };
 
             return options;
         }
@@ -95,6 +76,6 @@ namespace Vit.Linq.QueryBuilder.SystemTextJson
         }
 
 
-        
+
     }
 }

+ 1 - 27
src/Vit.Linq/QueryBuilder/FilterRule.cs

@@ -7,33 +7,7 @@ namespace Vit.Linq.QueryBuilder
     /// This class is used to define a hierarchical filter for a given collection. This type can be serialized/deserialized by JSON.NET without needing to modify the data structure from QueryBuilder.
     /// </summary>
     [ExcludeFromCodeCoverage]
-    public class FilterRule : IFilterRule
+    public class FilterRule : FilterRuleBase<FilterRule>
     {
-        /// <summary>
-        /// condition - acceptable values are "and" and "or".
-        /// </summary>
-        public string condition { get; set; }
-
-
-        public string field { get; set; }
-
-
-        public string @operator { get; set; }
-
-        /// <summary>
-        ///  nested filter rules.
-        /// </summary>
-        public List<FilterRule> rules { get; set; }
-
-
-        /// <summary>
-        /// Gets or sets the value of the filter.
-        /// </summary>
-        /// <value>
-        /// The value.
-        /// </value>
-        public object value { get; set; }
-
-        IEnumerable<IFilterRule> IFilterRule.rules => rules;
     }
 }

+ 54 - 0
src/Vit.Linq/QueryBuilder/FilterRuleBase.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Vit.Linq.QueryBuilder
+{
+    /// <summary>
+    /// This class is used to define a hierarchical filter for a given collection. This type can be serialized/deserialized by JSON.NET without needing to modify the data structure from QueryBuilder.
+    /// </summary>
+    [ExcludeFromCodeCoverage]
+    public abstract class FilterRuleBase<RuleType> : IFilterRule
+        where RuleType : IFilterRule
+    {
+        /// <summary>
+        /// condition - acceptable values are "and" and "or".
+        /// </summary>
+        public virtual string condition { get; set; }
+
+
+        public virtual string field { get; set; }
+
+
+        public virtual string @operator { get; set; }
+
+        /// <summary>
+        ///  nested filter rules.
+        /// </summary>
+        public virtual List<RuleType> rules { get; set; }
+
+
+        /// <summary>
+        /// Gets or sets the value of the filter.
+        /// </summary>
+        /// <value>
+        /// The value.
+        /// </value>
+        public virtual object value { get; set; }
+
+        IEnumerable<IFilterRule> IFilterRule.rules => rules?.Select(r => (IFilterRule)r);
+
+
+        public virtual MemberExpression GetLeftValueExpression(ParameterExpression parameter)
+        {
+            return LinqHelp.GetFieldMemberExpression(parameter, field);
+        }
+
+        public virtual MemberExpression GetRightValueExpression(ParameterExpression parameter, Type valueType)
+        {
+            return LinqHelp.GetFieldMemberExpression(parameter, field);
+        }
+    }
+}

+ 4 - 0
src/Vit.Linq/QueryBuilder/IFilterRule.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using System.Linq.Expressions;
 
 namespace Vit.Linq.QueryBuilder
 {
@@ -40,5 +41,8 @@ namespace Vit.Linq.QueryBuilder
         /// value of the filter. Supported value types are "integer", "double", "string", "date", "datetime", and "boolean".
         /// </summary>
         object value { get; set; }
+
+
+        MemberExpression GetLeftValueExpression(ParameterExpression parameter);
     }
 }

+ 36 - 30
src/Vit.Linq/QueryBuilder/QueryBuilderService.cs

@@ -87,6 +87,12 @@ namespace Vit.Linq.QueryBuilder
             return value;
         }
 
+        protected virtual MemberExpression GetLeftValueExpression(IFilterRule rule, ParameterExpression parameter) 
+        {
+            return rule.GetLeftValueExpression(parameter);
+            //return LinqHelp.GetFieldMemberExpression(parameter, rule.field);
+        }
+
 
         Expression ConvertToExpression(IFilterRule rule, ParameterExpression parameter)
         {
@@ -104,11 +110,11 @@ namespace Vit.Linq.QueryBuilder
                 return null;
             }
 
-            MemberExpression memberExp = LinqHelp.GetFieldMemberExpression(parameter, rule.field);
+            MemberExpression leftValueExpression = GetLeftValueExpression(rule, parameter);
 
             #region Get Expression
-
-            Type fieldType = memberExp.Type;
+            // left field type
+            Type leftFieldType = leftValueExpression.Type;
 
             var Operator = GetOperator(rule);
             var cmpType = operatorIsIgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
@@ -130,29 +136,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 +178,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
 
@@ -217,28 +223,28 @@ namespace Vit.Linq.QueryBuilder
 
 
             #region Method ConvertValueExp
-            UnaryExpression ConvertValueExp()
+            UnaryExpression GetRightValueExpression()
             {
-                object value = GetRulePrimitiveValue(rule.value,rule,fieldType);
+                object value = GetRulePrimitiveValue(rule.value,rule,leftFieldType);
                 if (value != null)
                 {
-                    Type valueType = Nullable.GetUnderlyingType(fieldType) ?? fieldType;
+                    Type valueType = Nullable.GetUnderlyingType(leftFieldType) ?? leftFieldType;
                     value = Convert.ChangeType(value, valueType);
                 }
 
                 Expression<Func<object>> valueLamba = () => value;
-                return Expression.Convert(valueLamba.Body, fieldType);
+                return Expression.Convert(valueLamba.Body, 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));
             }
@@ -248,18 +254,18 @@ namespace Vit.Linq.QueryBuilder
                 Expression arrayExp = null;
                 #region build arrayExp
                 {
-                    Type valueType = typeof(IEnumerable<>).MakeGenericType(fieldType);
+                    Type valueType = typeof(IEnumerable<>).MakeGenericType(leftFieldType);
                     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);
+                        //value = Vit.Core.Module.Serialization.Json.Deserialize(Vit.Core.Module.Serialization.Json.Serialize(rule.value), valueType);
+                        value = ConvertToList(rule.value, rule, leftFieldType);
                     }
                     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);
+                var inCheck = Expression.Call(typeof(System.Linq.Enumerable), "Contains", new[] { leftFieldType }, arrayExp, leftValueExpression);
                 return inCheck;
             }
             #endregion