Explorar el Código

#gogs14_2024-01-19_SupportMethodLikeCount
1.support class method
2.support Array ('ba[0].name', 'ba.Length')
3.support List ('bList[0].name', 'bList.Count')

lith hace 1 año
padre
commit
280dd7d8ea
Se han modificado 24 ficheros con 476 adiciones y 105 borrados
  1. 29 1
      src/Test/Vit.Linq.MsTest/DataSource.cs
  2. 111 0
      src/Test/Vit.Linq.MsTest/QueryBuilder/Filter_TestBase.cs
  3. 1 1
      src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_FilterRule.cs
  4. 39 0
      src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_FilterRuleWithMethod.cs
  5. 1 1
      src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_Newtonsoft.cs
  6. 1 1
      src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_Newtonsoft2.cs
  7. 1 1
      src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_SystemTextJson.cs
  8. 1 1
      src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_SystemTextJson2.cs
  9. 1 1
      src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_FilterRule.cs
  10. 39 0
      src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_FilterRuleWithMethod.cs
  11. 7 6
      src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_Newtonsoft.cs
  12. 7 6
      src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_Newtonsoft2.cs
  13. 7 6
      src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_SystemTextJson.cs
  14. 8 8
      src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_SystemTextJson2.cs
  15. 1 1
      src/Vit.Linq.Extensions/Extensions/IQueryable_Sort_Extensions.cs
  16. 2 2
      src/Vit.Linq.Extensions/Extensions/Queryable_Sort_Extensions.cs
  17. 10 19
      src/Vit.Linq.NewtonsoftJson/FilterRule_Newtonsoft.cs
  18. 50 21
      src/Vit.Linq.SystemTextJson/FilterRule_SystemTextJson.cs
  19. 37 10
      src/Vit.Linq/LinqHelp.cs
  20. 107 0
      src/Vit.Linq/MoreFilter/FilterRuleWithMethod.cs
  21. 1 0
      src/Vit.Linq/QueryBuilder/FilterRule.cs
  22. 4 2
      src/Vit.Linq/QueryBuilder/FilterRuleBase.cs
  23. 3 3
      src/Vit.Linq/QueryBuilder/IFilterRule.cs
  24. 8 14
      src/Vit.Linq/QueryBuilder/QueryBuilderService.cs

+ 29 - 1
src/Test/Vit.Linq.MsTest/DataSource.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 
@@ -16,19 +17,46 @@ namespace Vit.Linq.MsTest
         public ModelB b1;
 
         public ModelB[] ba;
+
+        public List<ModelB> bList;
         public ModelA BuildB()
         {
             b1 = new ModelB { name = name + "_b1", pid = pid };
 
-            ba = new[] { b1 };
+            if (id % 2 == 0)
+                ba = new[] { b1, b1 };
+            else
+                ba = new[] { b1 };
+
+            bList = ba.ToList();
+          
             return this;
         }
+
+        public int GetBCount()
+        {
+            return bList.Count;
+        }
+        public bool BExistAtIndex(int index)
+        {
+            if (index < bList.Count) return true;
+            return false;
+        }
+        public ModelB GetBAtIndex(int index)
+        {
+            if (index < bList.Count) return bList[index];
+            return null;
+        }
     }
 
     public class ModelB
     {
         public int? pid;
         public string name;
+        public string GetBName()
+        {
+            return name;
+        }
     }
 
 

+ 111 - 0
src/Test/Vit.Linq.MsTest/QueryBuilder/Filter_TestBase.cs

@@ -5,6 +5,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
 
+using Vit.Linq.MoreFilter;
 using Vit.Linq.QueryBuilder;
 
 namespace Vit.Linq.MsTest.QueryBuilder
@@ -531,6 +532,116 @@ namespace Vit.Linq.MsTest.QueryBuilder
             }
             #endregion
 
+            #region #7 Array
+            {
+                var query = GetQueryable();
+                var strRule = "{'field':'ba[0].name',  'operator': '=',  'value': 'name987_b1' }".Replace("'", "\"");
+                var rule = GetRule(strRule);
+
+                var result = Filter(ToQuery(query), rule);
+
+                Assert.AreEqual(1, result.Count);
+                Assert.AreEqual(987, result[0].id);
+            }
+            {
+                var query = GetQueryable();
+                var strRule = "{'field':'ba.0.name',  'operator': '=',  'value': 'name987_b1' }".Replace("'", "\"");
+                var rule = GetRule(strRule);
+
+                var result = Filter(ToQuery(query), rule);
+
+                Assert.AreEqual(1, result.Count);
+                Assert.AreEqual(987, result[0].id);
+            }
+            {
+                var query = GetQueryable();
+                var strRule = "{'field':'ba.Length',  'operator': '=',  'value': 1 }".Replace("'", "\"");
+                var rule = GetRule(strRule);
+
+                var result = Filter(ToQuery(query), rule);
+
+                Assert.AreEqual(500, result.Count);
+            }
+            #endregion
+
+            #region #8 List
+            {
+                var query = GetQueryable();
+                var strRule = "{'field':'bList[0].name',  'operator': '=',  'value': 'name987_b1' }".Replace("'", "\"");
+                var rule = GetRule(strRule);
+
+                var result = Filter(ToQuery(query), rule);
+
+                Assert.AreEqual(1, result.Count);
+                Assert.AreEqual(987, result[0].id);
+            }
+            {
+                var query = GetQueryable();
+                var strRule = "{'field':'bList.0.name',  'operator': '=',  'value': 'name987_b1' }".Replace("'", "\"");
+                var rule = GetRule(strRule);
+
+                var result = Filter(ToQuery(query), rule);
+
+                Assert.AreEqual(1, result.Count);
+                Assert.AreEqual(987, result[0].id);
+            }
+            {
+                var query = GetQueryable();
+                var strRule = "{'field':'bList.Count',  'operator': '=',  'value': 1 }".Replace("'", "\"");
+                var rule = GetRule(strRule);
+
+                var result = Filter(ToQuery(query), rule);
+
+                Assert.AreEqual(500, result.Count);
+            }
+            #endregion
+
+            #region #9  method in fields
+            if (FilterRuleWithMethod.SupportFieldMethod(GetRule("{}")))
+            {
+                {
+                    var query = GetQueryable();
+                    var strRule = "{'field':'bList[0]', 'fields':[ {'method':'GetBName' }] ,  'operator': '=',  'value': 'name987_b1' }".Replace("'", "\"");
+                    var rule = GetRule(strRule);
+
+                    var result = Filter(ToQuery(query), rule);
+
+                    Assert.AreEqual(1, result.Count);
+                    Assert.AreEqual(987, result[0].id);
+                }
+                {
+                    var query = GetQueryable();
+                    var strRule = "{'fields':[ { 'method':'GetBCount'}] ,    'operator': '=',  'value': 1 }".Replace("'", "\"");
+                    var rule = GetRule(strRule);
+
+                    var result = Filter(ToQuery(query), rule);
+
+                    Assert.AreEqual(500, result.Count);
+                }
+
+                {
+                    var query = GetQueryable();
+                    var strRule = "{ 'fields':[ {'method':'GetBAtIndex', 'methodParameters':[0] }, {'field':'name'}] ,  'operator': '=',  'value': 'name987_b1' }".Replace("'", "\"");
+                    var rule = GetRule(strRule);
+
+                    var result = Filter(ToQuery(query), rule);
+
+                    Assert.AreEqual(1, result.Count);
+                    Assert.AreEqual(987, result[0].id);
+                }
+
+                {
+                    var query = GetQueryable();
+                    var strRule = "{ 'fields':[ {'method':'GetBAtIndex', 'methodParameters':[1] }] ,  'operator': 'IsNull' }".Replace("'", "\"");
+                    var rule = GetRule(strRule);
+
+                    var result = Filter(ToQuery(query), rule);
+
+                    Assert.AreEqual(500, result.Count);
+                }
+            }
+            #endregion
+
         }
 
 

+ 1 - 1
src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test.cs → src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_FilterRule.cs

@@ -11,7 +11,7 @@ using Queryable = System.Linq.IQueryable;
 namespace Vit.Linq.MsTest.QueryBuilder.IQueryableTest
 {
     [TestClass]
-    public class Filter_Test : Filter_TestBase<Queryable>
+    public class Filter_Test_FilterRule : Filter_TestBase<Queryable>
     {
 
         [TestMethod]

+ 39 - 0
src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_FilterRuleWithMethod.cs

@@ -0,0 +1,39 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Vit.Core.Module.Serialization;
+using Vit.Linq.QueryBuilder;
+using Vit.Linq.MoreFilter;
+using Newtonsoft.Json.Linq;
+using System;
+
+namespace Vit.Linq.MsTest.QueryBuilder.IQueryableTest
+{
+    [TestClass]
+    public class Filter_Test_FilterRuleWithMethod : Filter_Test_FilterRule
+    {
+        [TestMethod]
+        public void Test_FilterRule()
+        {
+            base.TestFilterRule();
+        }
+
+        public override IFilterRule GetRule(string filterRule)
+        {
+            return Json.Deserialize<FilterRuleWithMethod>(filterRule);
+        }
+
+        public virtual QueryBuilderService GetService()
+        {
+            QueryBuilderService service = new QueryBuilderService();
+            service.GetRuleValue = (object value, IFilterRule rule, Type fieldType) =>
+            {
+                // to deal with null value
+                if (value is JValue jv) return jv.Value;
+                return value;
+            };
+            return service;
+        }
+
+    }
+}
+
+

+ 1 - 1
src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_Newtonsoft.cs

@@ -7,7 +7,7 @@ using Vit.Linq.QueryBuilder.NewtonsoftJson;
 namespace Vit.Linq.MsTest.QueryBuilder.IQueryableTest
 {
     [TestClass]
-    public class Filter_Test_Newtonsoft : Filter_Test
+    public class Filter_Test_Newtonsoft : Filter_Test_FilterRule
     {
 
         public override IFilterRule GetRule(string filterRule)

+ 1 - 1
src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_Newtonsoft2.cs

@@ -6,7 +6,7 @@ using Vit.Linq.QueryBuilder.NewtonsoftJson;
 namespace Vit.Linq.MsTest.QueryBuilder.IQueryableTest
 {
     [TestClass]
-    public class Filter_Test_Newtonsoft2 : Filter_Test
+    public class Filter_Test_Newtonsoft2 : Filter_Test_FilterRule
     {
 
         public override IFilterRule GetRule(string filterRule)

+ 1 - 1
src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_SystemTextJson.cs

@@ -8,7 +8,7 @@ using Vit.Linq.QueryBuilder.SystemTextJson;
 namespace Vit.Linq.MsTest.QueryBuilder.IQueryableTest
 {
     [TestClass]
-    public class Filter_Test_SystemTextJson : Filter_Test
+    public class Filter_Test_SystemTextJson : Filter_Test_FilterRule
     {
 
         public override IFilterRule GetRule(string filterRule)

+ 1 - 1
src/Test/Vit.Linq.MsTest/QueryBuilder/IQueryableTest/Filter_Test_SystemTextJson2.cs

@@ -6,7 +6,7 @@ using Vit.Linq.QueryBuilder.SystemTextJson;
 namespace Vit.Linq.MsTest.QueryBuilder.IQueryableTest
 {
     [TestClass]
-    public class Filter_Test_SystemTextJson2 : Filter_Test
+    public class Filter_Test_SystemTextJson2 : Filter_Test_FilterRule
     {
 
         public override IFilterRule GetRule(string filterRule)

+ 1 - 1
src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test.cs → src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_FilterRule.cs

@@ -11,7 +11,7 @@ using Queryable = System.Linq.IQueryable<Vit.Linq.MsTest.ModelA>;
 namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
 {
     [TestClass]
-    public class Filter_Test : Filter_TestBase<Queryable>
+    public class Filter_Test_FilterRule : Filter_TestBase<Queryable>
     {
 
         [TestMethod]

+ 39 - 0
src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_FilterRuleWithMethod.cs

@@ -0,0 +1,39 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Vit.Core.Module.Serialization;
+using Vit.Linq.QueryBuilder;
+using Vit.Linq.MoreFilter;
+using Newtonsoft.Json.Linq;
+using System;
+
+namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
+{
+    [TestClass]
+    public class Filter_Test_FilterRuleWithMethod : Filter_Test_FilterRule
+    {
+        [TestMethod]
+        public void Test_FilterRule()
+        {
+            base.TestFilterRule();
+        }
+
+        public override IFilterRule GetRule(string filterRule)
+        {
+            return Json.Deserialize<FilterRuleWithMethod>(filterRule);
+        }
+
+        public virtual QueryBuilderService GetService()
+        {
+            QueryBuilderService service = new QueryBuilderService();
+            service.GetRuleValue = (object value, IFilterRule rule, Type fieldType) =>
+            {
+                // to deal with null value
+                if (value is JValue jv) return jv.Value;
+                return value;
+            };
+            return service;
+        }
+
+    }
+}
+
+

+ 7 - 6
src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_Newtonsoft.cs

@@ -7,9 +7,15 @@ using Vit.Linq.QueryBuilder.NewtonsoftJson;
 namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
 {
     [TestClass]
-    public class Filter_Test_Newtonsoft : Filter_Test
+    public class Filter_Test_Newtonsoft : Filter_Test_FilterRule
     {
 
+        [TestMethod]
+        public void Test_FilterRule()
+        {
+            base.TestFilterRule();
+        }
+
         public override IFilterRule GetRule(string filterRule)
         {
             return Json.Deserialize<FilterRule_Newtonsoft>(filterRule);
@@ -22,10 +28,5 @@ namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
         }
 
 
-        [TestMethod]
-        public void Test_FilterRule()
-        {
-            base.TestFilterRule();
-        }
     }
 }

+ 7 - 6
src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_Newtonsoft2.cs

@@ -6,8 +6,13 @@ using Vit.Linq.QueryBuilder.NewtonsoftJson;
 namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
 {
     [TestClass]
-    public class Filter_Test_Newtonsoft2 : Filter_Test
+    public class Filter_Test_Newtonsoft2 : Filter_Test_FilterRule
     {
+        [TestMethod]
+        public void Test_FilterRule()
+        {
+            base.TestFilterRule();
+        }
 
         public override IFilterRule GetRule(string filterRule)
         {
@@ -19,11 +24,7 @@ namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
             return service;
         }
 
-        [TestMethod]
-        public void Test_FilterRule()
-        {
-            base.TestFilterRule();
-        }
+
 
     }
 }

+ 7 - 6
src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_SystemTextJson.cs

@@ -8,8 +8,13 @@ using Vit.Linq.QueryBuilder.SystemTextJson;
 namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
 {
     [TestClass]
-    public class Filter_Test_SystemTextJson : Filter_Test
+    public class Filter_Test_SystemTextJson : Filter_Test_FilterRule
     {
+        [TestMethod]
+        public void Test_FilterRule()
+        {
+            base.TestFilterRule();
+        }
 
         public override IFilterRule GetRule(string filterRule)
         {
@@ -23,10 +28,6 @@ namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
         }
 
 
-        [TestMethod]
-        public void Test_FilterRule()
-        {
-            base.TestFilterRule();
-        }
+
     }
 }

+ 8 - 8
src/Test/Vit.Linq.MsTest/QueryBuilder/QueryableTest/Filter_Test_SystemTextJson2.cs

@@ -6,24 +6,24 @@ using Vit.Linq.QueryBuilder.SystemTextJson;
 namespace Vit.Linq.MsTest.QueryBuilder.QueryableTest
 {
     [TestClass]
-    public class Filter_Test_SystemTextJson2 : Filter_Test
+    public class Filter_Test_SystemTextJson2 : Filter_Test_FilterRule
     {
+        [TestMethod]
+        public void Test_FilterRule()
+        {
+            base.TestFilterRule();
+        }
+
 
         public override IFilterRule GetRule(string filterRule)
         {
             return FilterRule_SystemTextJson.FromString(filterRule);
         }
+
         public override QueryBuilderService GetService()
         {
             QueryBuilderService service = new QueryBuilderService();
             return service;
         }
-
-        [TestMethod]
-        public void Test_FilterRule()
-        {
-            base.TestFilterRule();
-        }
-
     }
 }

+ 1 - 1
src/Vit.Linq.Extensions/Extensions/IQueryable_Sort_Extensions.cs

@@ -42,7 +42,7 @@ namespace Vit.Extensions.Linq_Extensions
             foreach (var item in sort)
             {
                 // get memberExp
-                MemberExpression memberExp = LinqHelp.GetFieldMemberExpression(parameter, item.field);
+                Expression memberExp = LinqHelp.GetFieldMemberExpression(parameter, item.field);
 
 
                 #region (x.2)Call

+ 2 - 2
src/Vit.Linq.Extensions/Extensions/Queryable_Sort_Extensions.cs

@@ -31,7 +31,7 @@ namespace Vit.Extensions.Linq_Extensions
             foreach (var item in sort)
             {
 
-                MemberExpression memberExp = LinqHelp.GetFieldMemberExpression(paramExp, item.field);
+                var memberExp = LinqHelp.GetFieldMemberExpression(paramExp, item.field);
                 LambdaExpression exp = Expression.Lambda(memberExp, paramExp);
 
                 if (orderedQuery == null)
@@ -62,7 +62,7 @@ namespace Vit.Extensions.Linq_Extensions
             if (string.IsNullOrEmpty(field)) return query;
 
             var paramExp = Expression.Parameter(typeof(T));
-            MemberExpression memberExp = LinqHelp.GetFieldMemberExpression(paramExp, field);
+            var memberExp = LinqHelp.GetFieldMemberExpression(paramExp, field);
             LambdaExpression expr = Expression.Lambda(memberExp, paramExp);
 
             return OrderBy(query, expr, asc);

+ 10 - 19
src/Vit.Linq.NewtonsoftJson/FilterRule_Newtonsoft.cs

@@ -5,36 +5,27 @@ using System.Diagnostics.CodeAnalysis;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 
+using Vit.Linq.MoreFilter;
+
 namespace Vit.Linq.QueryBuilder.NewtonsoftJson
 {
     /// <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 class FilterRule_Newtonsoft : FilterRuleBase<FilterRule_Newtonsoft>
+    public class FilterRule_Newtonsoft : FilterRuleWithMethod<FilterRule_Newtonsoft>
     {
-        /// <summary>
-        /// Gets or sets the value of the filter.
-        /// </summary>
-        /// <value>
-        /// The value.
-        /// </value>
-        public override object value
+
+        protected override object GetPrimitiveValue(Object value)
         {
-            get
+            if (value is JToken item)
             {
-                if (_value is JToken jt)
-                {
-                    return GetPrimitiveValue(jt);
-                }
-                return _value;
+                return GetPrimitiveValueFromJson(item);
             }
-            set => _value = value;
+            return value;
         }
 
-        private object _value;
 
- 
 
 
         public static FilterRule_Newtonsoft FromString(string filter)
@@ -45,7 +36,7 @@ namespace Vit.Linq.QueryBuilder.NewtonsoftJson
         static readonly global::Newtonsoft.Json.JsonSerializerSettings serializeSetting = new global::Newtonsoft.Json.JsonSerializerSettings() { Converters = { new ValueConverter() } };
 
 
-        public static object GetPrimitiveValue(JToken value)
+        public static object GetPrimitiveValueFromJson(JToken value)
         {
             if (value is JValue jv)
             {
@@ -75,7 +66,7 @@ namespace Vit.Linq.QueryBuilder.NewtonsoftJson
             public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
             {
                 JToken token = JToken.Load(reader);
-                return GetPrimitiveValue(token);
+                return GetPrimitiveValueFromJson(token);
             }
 
             public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)

+ 50 - 21
src/Vit.Linq.SystemTextJson/FilterRule_SystemTextJson.cs

@@ -1,40 +1,29 @@
 using System;
-using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Text.Json;
+using System.Text.Json.Serialization;
 using System.Text.Unicode;
 
+using Vit.Linq.MoreFilter;
+
 namespace Vit.Linq.QueryBuilder.SystemTextJson
 {
     /// <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 class FilterRule_SystemTextJson : FilterRuleBase<FilterRule_SystemTextJson>
+    public class FilterRule_SystemTextJson : FilterRuleWithMethod<FilterRule_SystemTextJson>
     {
-        /// <summary>
-        /// Gets or sets the value of the filter.
-        /// </summary>
-        /// <value>
-        /// The value.
-        /// </value>
-        public override object value
+        protected override object GetPrimitiveValue(Object value)
         {
-            get
+            if (value is JsonElement je)
             {
-                if (_value is JsonElement je)
-                {
-                    return GetPrimitiveValue(je);
-                }
-                return _value;
+                return GetPrimitiveValueFromJson(je);
             }
-            set => _value = value;
+            return value;
         }
 
-        private object _value;
-
-
         public static FilterRule_SystemTextJson FromString(string filter)
         {
             return JsonSerializer.Deserialize<FilterRule_SystemTextJson>(filter, options);
@@ -53,12 +42,15 @@ namespace Vit.Linq.QueryBuilder.SystemTextJson
                 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
             };
 
+            options.Converters.Add(new CustomObjectConverter());
+
             return options;
         }
 
 
 
-        public static object GetPrimitiveValue(JsonElement value)
+
+        public static object GetPrimitiveValueFromJson(JsonElement value)
         {
             switch (value.ValueKind)
             {
@@ -69,13 +61,50 @@ namespace Vit.Linq.QueryBuilder.SystemTextJson
                 case JsonValueKind.Number: return value.GetDecimal();
                 case JsonValueKind.String: return value.GetString();
                 case JsonValueKind.Array:
-                    return value.EnumerateArray().Select(GetPrimitiveValue).ToList();
+                    return value.EnumerateArray().Select(GetPrimitiveValueFromJson).ToList();
             }
 
             return value;
         }
 
 
+        class CustomObjectConverter : JsonConverter<object>
+        {
+            public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+            {
+                switch (reader.TokenType)
+                {
+                    case JsonTokenType.Number:
+                        if (reader.TryGetInt32(out int intValue))
+                        {
+                            return intValue;
+                        }
+                        if (reader.TryGetDouble(out double doubleValue))
+                        {
+                            return doubleValue;
+                        }
+                        break;
+                    case JsonTokenType.True:
+                        return true;
+                    case JsonTokenType.False:
+                        return false;
+                    case JsonTokenType.String:
+                        return reader.GetString();
+                    case JsonTokenType.Null:
+                        return null;
+                }
+                using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
+                {
+                    return doc.RootElement.Clone();
+                }
+            }
+
+            public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
+            {
+                JsonSerializer.Serialize(writer, value, value.GetType(), options);
+            }
+        }
+
 
     }
 }

+ 37 - 10
src/Vit.Linq/LinqHelp.cs

@@ -1,13 +1,37 @@
 using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
 using System.Linq.Expressions;
 
 namespace Vit.Linq.QueryBuilder
 {
     public partial class LinqHelp
     {
-
-        public static MemberExpression GetFieldMemberExpression_ByName(Expression parameter, string propertyOrFieldName)
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="parameter"></param>
+        /// <param name="propertyOrFieldName"> could be array index, example:  "2"  "name"</param>
+        /// <returns></returns>
+        public static Expression GetFieldMemberExpression_ByName(Expression parameter, string propertyOrFieldName)
         {
+            var valueType = parameter.Type;
+            int index;
+            if (valueType.IsArray)
+            {
+                // Array
+                if (int.TryParse(propertyOrFieldName, out index))
+                    return Expression.ArrayAccess(parameter, Expression.Constant(index));
+            }
+            else
+            if (valueType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(valueType))
+            {
+                // IEnumerable<>    List<>
+                if (int.TryParse(propertyOrFieldName, out index))
+                    return Expression.Call(typeof(Enumerable), "ElementAt", valueType.GetGenericArguments(), parameter, Expression.Constant(index));
+            }
+
             return Expression.PropertyOrField(parameter, propertyOrFieldName);
         }
 
@@ -15,16 +39,19 @@ namespace Vit.Linq.QueryBuilder
         /// 
         /// </summary>
         /// <param name="parameter"></param>
-        /// <param name="fieldPath"> could be nasted , example: "name"  "depart.name"</param>
+        /// <param name="fieldPath"> could be nasted , example: "name"  "depart.name"  "departs[1].name" "departs.1.name"</param>
         /// <returns></returns>
-        public static MemberExpression GetFieldMemberExpression(ParameterExpression parameter, string fieldPath)
+        public static Expression GetFieldMemberExpression(Expression parameter, string fieldPath)
         {
-            MemberExpression memberExp = null;
-            foreach (var fieldName in fieldPath?.Split('.'))
+            fieldPath = fieldPath?.Replace("]", "").Replace("[", ".");
+            if (!string.IsNullOrWhiteSpace(fieldPath))
             {
-                memberExp = GetFieldMemberExpression_ByName(((Expression)memberExp) ?? parameter, fieldName);
+                foreach (var fieldName in fieldPath.Split('.'))
+                {
+                    parameter = GetFieldMemberExpression_ByName(parameter, fieldName);
+                }
             }
-            return memberExp;
+            return parameter;
         }
 
 
@@ -34,7 +61,7 @@ namespace Vit.Linq.QueryBuilder
         /// <param name="type"></param>
         /// <param name="fieldPath"> could be nasted , example: "name"  "depart.name"</param>
         /// <returns></returns>
-        public static MemberExpression GetFieldMemberExpression(Type type, string fieldPath)
+        public static Expression GetFieldMemberExpression(Type type, string fieldPath)
         {
             return GetFieldMemberExpression(Expression.Parameter(type), fieldPath);
         }
@@ -44,7 +71,7 @@ namespace Vit.Linq.QueryBuilder
         public static Expression<Func<T, object>> GetFieldExpression<T>(string fieldPath)
         {
             var parammeter = Expression.Parameter(typeof(T));
-            MemberExpression memberExp = GetFieldMemberExpression(parammeter, fieldPath);
+            Expression memberExp = GetFieldMemberExpression(parammeter, fieldPath);
             var lambda = Expression.Lambda(memberExp, parammeter).Compile();
             return t => lambda.DynamicInvoke(t);
         }

+ 107 - 0
src/Vit.Linq/MoreFilter/FilterRuleWithMethod.cs

@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq.Expressions;
+using System.Linq;
+using Vit.Linq.QueryBuilder;
+
+namespace Vit.Linq.MoreFilter
+{
+    internal interface IMethods { }
+
+    [ExcludeFromCodeCoverage]
+    public class FilterRuleWithMethod : FilterRuleWithMethod<FilterRuleWithMethod>
+    {
+        public static bool SupportFieldMethod(IFilterRule filter)
+        {
+            return typeof(IMethods).IsAssignableFrom(filter.GetType());
+        }
+    }
+
+
+
+    /// <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 class FilterRuleWithMethod<RuleType> : FilterRuleBase<RuleType>, IMethods
+               where RuleType : IFilterRule
+    {
+        public class Field
+        {
+            public string field { get; set; }
+            public string method { get; set; }
+
+            public object[] methodParameters { get; set; }
+        }
+
+        public virtual List<Field> fields { get; set; }
+
+
+        public virtual Expression GetValueExpression(Expression valueExpression, Field field)
+        {
+            if (!string.IsNullOrWhiteSpace(field.field))
+            {
+                valueExpression = LinqHelp.GetFieldMemberExpression(valueExpression, field.field);
+            }
+
+            if (!string.IsNullOrWhiteSpace(field.method))
+            {
+                var paramCount = field.methodParameters?.Length ?? 0;
+                var valueType = valueExpression.Type;
+                var Method = valueType.GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
+                    ?.FirstOrDefault(m => m.Name == field.method && m.GetParameters().Length == paramCount);
+                if (Method != null)
+                {
+                    if (paramCount == 0)
+                    {
+                        valueExpression = Expression.Call(valueExpression, Method);
+                    }
+                    else
+                    {
+                        var argExpressions = Method.GetParameters().Select((paras, index) =>
+                        {
+                            var value = GetPrimitiveValue(field.methodParameters[index]);
+                            value = Convert.ChangeType(value, paras.ParameterType);
+                            return Expression.Constant(value);
+                        }).ToList();
+
+                        valueExpression = Expression.Call(valueExpression, Method, argExpressions);
+                    }
+                }
+            }
+            return valueExpression;
+        }
+
+        public override Expression GetLeftValueExpression(Expression valueExpression)
+        {
+            valueExpression = base.GetLeftValueExpression(valueExpression);
+
+            fields?.ForEach(field => { valueExpression = GetValueExpression(valueExpression, field); });
+
+            return valueExpression;
+        }
+
+
+        protected virtual object GetPrimitiveValue(Object value) => value;
+
+
+        /// <summary>
+        /// Gets or sets the value of the filter.
+        /// </summary>
+        /// <value>
+        /// The value.
+        /// </value>
+        public override object value
+        {
+            get => GetPrimitiveValue(_value);
+            set => _value = value;
+        }
+
+        private object _value;
+
+
+
+
+    }
+}

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

@@ -9,5 +9,6 @@ namespace Vit.Linq.QueryBuilder
     [ExcludeFromCodeCoverage]
     public class FilterRule : FilterRuleBase<FilterRule>
     {
+
     }
 }

+ 4 - 2
src/Vit.Linq/QueryBuilder/FilterRuleBase.cs

@@ -41,9 +41,11 @@ namespace Vit.Linq.QueryBuilder
         IEnumerable<IFilterRule> IFilterRule.rules => rules?.Select(r => (IFilterRule)r);
 
 
-        public virtual MemberExpression GetLeftValueExpression(ParameterExpression parameter)
+        public virtual Expression GetLeftValueExpression(Expression valueExpression)
         {
-            return LinqHelp.GetFieldMemberExpression(parameter, field);
+            if (!string.IsNullOrWhiteSpace(field))
+                valueExpression = LinqHelp.GetFieldMemberExpression(valueExpression, field);
+            return valueExpression;
         }
 
     }

+ 3 - 3
src/Vit.Linq/QueryBuilder/IFilterRule.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.Linq.Expressions;
 
 namespace Vit.Linq.QueryBuilder
@@ -42,7 +43,6 @@ namespace Vit.Linq.QueryBuilder
         /// </summary>
         object value { get; set; }
 
-
-        MemberExpression GetLeftValueExpression(ParameterExpression parameter);
+        Expression GetLeftValueExpression(Expression valueExpression);
     }
 }

+ 8 - 14
src/Vit.Linq/QueryBuilder/QueryBuilderService.cs

@@ -64,9 +64,6 @@ namespace Vit.Linq.QueryBuilder
         }
 
 
-
-
-
         public virtual ECondition GetCondition(IFilterRule filter)
         {
             return filter.condition?.ToLower() == "or" ? ECondition.or : ECondition.and;
@@ -74,10 +71,9 @@ namespace Vit.Linq.QueryBuilder
 
 
 
-        protected virtual MemberExpression GetLeftValueExpression(IFilterRule rule, ParameterExpression parameter)
+        protected virtual Expression GetLeftValueExpression(IFilterRule rule, ParameterExpression valueExpression)
         {
-            return rule.GetLeftValueExpression(parameter);
-            //return LinqHelp.GetFieldMemberExpression(parameter, rule.field);
+            return rule.GetLeftValueExpression(valueExpression); 
         }
 
 
@@ -102,7 +98,7 @@ namespace Vit.Linq.QueryBuilder
 
 
 
-        protected virtual UnaryExpression GetRightValueExpression(IFilterRule rule, ParameterExpression parameter, Type valueType)
+        protected virtual Expression GetRightValueExpression(IFilterRule rule, ParameterExpression parameter, Type valueType)
         {
             object rightValue = rule.value;
 
@@ -179,16 +175,15 @@ namespace Vit.Linq.QueryBuilder
             }
 
             // #2 simple rule
-            if (string.IsNullOrWhiteSpace(rule.field))
+            if (string.IsNullOrWhiteSpace(rule.@operator))
             {
                 return null;
             }
 
-            MemberExpression leftValueExpression = GetLeftValueExpression(rule, parameter);
+            Expression leftValueExpression = GetLeftValueExpression(rule, parameter);
+            Type leftFieldType = leftValueExpression.Type;
 
             #region Get Expression
-            // left field type
-            Type leftFieldType = leftValueExpression.Type;
 
             var Operator = GetOperator(rule);
             var cmpType = operatorIsIgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
@@ -296,13 +291,12 @@ namespace Vit.Linq.QueryBuilder
             return null;
 
 
-            #region Method ConvertValueExp
-            UnaryExpression GetRightValueExpression()
+            #region inner Method
+            Expression GetRightValueExpression()
             {
                 return this.GetRightValueExpression(rule, parameter, leftFieldType);
             }
 
-
             Expression IsNull()
             {
                 var isNullable = !leftFieldType.IsValueType || Nullable.GetUnderlyingType(leftFieldType) != null;