Parcourir la source

added filter dbo; added filter in crud interface; added npgsql int.ToString method support

tags/v0.1.0
Robin Thoni il y a 8 ans
Parent
révision
5a232d33f5

+ 9
- 2
Luticate2.Utils/Business/LuCrudBusiness.cs Voir le fichier

@@ -1,6 +1,7 @@
1 1
 using System;
2 2
 using System.Collections.Generic;
3 3
 using Luticate2.Utils.Dbo.Basic;
4
+using Luticate2.Utils.Dbo.Filter;
4 5
 using Luticate2.Utils.Dbo.OrderBy;
5 6
 using Luticate2.Utils.Dbo.Result;
6 7
 using Luticate2.Utils.Interfaces;
@@ -161,11 +162,17 @@ namespace Luticate2.Utils.Business
161 162
             return DataAccess.GetSingleById(id);
162 163
         }
163 164
 
165
+
166
+        public LuResult<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, LuFilterDbo filter,
167
+            int page = 0, int perPage = int.MaxValue)
168
+        {
169
+            return DataAccess.GetMultiple(orderBy, filter, page, perPage);
170
+        }
171
+
164 172
         public LuResult<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, int page = 0,
165 173
             int perPage = int.MaxValue)
166 174
         {
167
-            var res = DataAccess.GetMultiple(orderBy, page, perPage);
168
-            return res;
175
+            return DataAccess.GetMultiple(orderBy, page, perPage);
169 176
         }
170 177
 
171 178
 

+ 4
- 2
Luticate2.Utils/Controllers/LuCrudController.cs Voir le fichier

@@ -2,6 +2,7 @@
2 2
 using System.Linq;
3 3
 using Luticate2.Utils.Dbo;
4 4
 using Luticate2.Utils.Dbo.Basic;
5
+using Luticate2.Utils.Dbo.Filter;
5 6
 using Luticate2.Utils.Dbo.OrderBy;
6 7
 using Luticate2.Utils.Interfaces;
7 8
 using Microsoft.AspNetCore.Mvc;
@@ -30,9 +31,10 @@ namespace Luticate2.Utils.Controllers
30 31
 
31 32
         [HttpGet]
32 33
         [Route("[controller]")]
33
-        public LuApiWrapperDbo<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, int page = 0, int perPage = int.MaxValue)
34
+        public LuApiWrapperDbo<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, LuFilterDbo filter,
35
+            int page = 0, int perPage = int.MaxValue)
34 36
         {
35
-            return Handle(Busines.GetMultiple(orderBy, page, perPage));
37
+            return Handle(Busines.GetMultiple(orderBy, filter, page, perPage));
36 38
         }
37 39
 
38 40
         [HttpPost]

+ 16
- 1
Luticate2.Utils/Controllers/LuUtilsExtensions.cs Voir le fichier

@@ -1,12 +1,16 @@
1 1
 using System.Collections.Generic;
2
+using Luticate2.Utils.DataAccess.Npgsql;
2 3
 using Luticate2.Utils.Dbo.Basic;
4
+using Luticate2.Utils.Dbo.Filter;
3 5
 using Luticate2.Utils.Dbo.OrderBy;
4 6
 using Luticate2.Utils.Dbo.Result;
5 7
 using Luticate2.Utils.Middlewares;
6 8
 using Microsoft.AspNetCore.Builder;
7 9
 using Microsoft.AspNetCore.Http;
8 10
 using Microsoft.AspNetCore.Mvc;
11
+using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators.Internal;
9 12
 using Microsoft.Extensions.DependencyInjection;
13
+using Microsoft.Extensions.DependencyInjection.Extensions;
10 14
 
11 15
 namespace Luticate2.Utils.Controllers
12 16
 {
@@ -23,10 +27,21 @@ namespace Luticate2.Utils.Controllers
23 27
             return services;
24 28
         }
25 29
 
30
+        public static IServiceCollection AddEntityFrameworkNpgsqlLuticate(this IServiceCollection services)
31
+        {
32
+            services.TryAdd(new ServiceCollection()
33
+                .AddScoped<NpgsqlCompositeMethodCallTranslator, NpgsqlCompositeMethodCallTranslatorLuticate>());
34
+            return services;
35
+        }
36
+
26 37
         public static IMvcBuilder AddLuticateUtils(this IMvcBuilder builder)
27 38
         {
28 39
             builder.Services.Configure<MvcOptions>(
29
-                options => options.ModelBinderProviders.Insert(0, new LuOrderByBinderProvider()));
40
+                options =>
41
+                {
42
+                    options.ModelBinderProviders.Insert(0, new LuOrderByBinderProvider());
43
+                    options.ModelBinderProviders.Insert(0, new LuFilterBinderProvider());
44
+                });
30 45
             return builder;
31 46
         }
32 47
 

+ 28
- 3
Luticate2.Utils/DataAccess/LuEfCrudDataAccess.cs Voir le fichier

@@ -2,7 +2,9 @@
2 2
 using System.Collections.Generic;
3 3
 using System.Linq;
4 4
 using System.Linq.Expressions;
5
+using Luticate2.Utils.DataAccess.Npgsql;
5 6
 using Luticate2.Utils.Dbo.Basic;
7
+using Luticate2.Utils.Dbo.Filter;
6 8
 using Luticate2.Utils.Dbo.OrderBy;
7 9
 using Luticate2.Utils.Dbo.Result;
8 10
 using Luticate2.Utils.Interfaces;
@@ -43,6 +45,11 @@ namespace Luticate2.Utils.DataAccess
43 45
             return exp;
44 46
         }
45 47
 
48
+        protected virtual Expression<Func<TModel, bool>> GetFilterExpression(LuFilterDbo filter)
49
+        {
50
+            return model => true;
51
+        }
52
+
46 53
         protected Func<TDboRead, T> GetIdFunc<T>()
47 54
         {
48 55
             return x => ((dynamic) x).Id;
@@ -69,6 +76,11 @@ namespace Luticate2.Utils.DataAccess
69 76
             return LuResult<T>.Error(LuStatus.NotFound, typeof(TModel).Name + ": Value not found", "");
70 77
         }
71 78
 
79
+        protected IQueryable<TModel> GetFilterQuery(LuFilterDbo filter)
80
+        {
81
+            return Table.Where(GetFilterExpression(filter));
82
+        }
83
+
72 84
 
73 85
 
74 86
 
@@ -206,11 +218,15 @@ namespace Luticate2.Utils.DataAccess
206 218
             return GetMultiple(orderBy, x => true, page, perPage, otherOrderBy);
207 219
         }
208 220
 
209
-        public LuResult<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, int page = 0, int perPage = int.MaxValue)
221
+        public LuResult<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, LuFilterDbo filter,
222
+            int page = 0, int perPage = int.MaxValue)
210 223
         {
211 224
             return Execute(() =>
212 225
             {
213
-                var count = Table.Count();
226
+                var queryable = GetFilterQuery(filter);
227
+                var v = new ExpressionVisitorDebugger();
228
+                v.Visit(queryable.Expression);
229
+                var count = queryable.Count();
214 230
                 IOrderedQueryable<TModel> ordered = null;
215 231
                 foreach (var field in orderBy.Fields)
216 232
                 {
@@ -226,7 +242,7 @@ namespace Luticate2.Utils.DataAccess
226 242
                     }
227 243
                     else
228 244
                     {
229
-                        ordered = field.Asc ? Table.OrderBy(exp) : Table.OrderByDescending(exp);
245
+                        ordered = field.Asc ? queryable.OrderBy(exp) : queryable.OrderByDescending(exp);
230 246
                     }
231 247
                 }
232 248
 
@@ -240,6 +256,15 @@ namespace Luticate2.Utils.DataAccess
240 256
             });
241 257
         }
242 258
 
259
+        public LuResult<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, int page = 0, int perPage = int.MaxValue)
260
+        {
261
+            var filter = new LuFilterDbo
262
+            {
263
+                Query = ""
264
+            };
265
+            return GetMultiple(orderBy, filter, page, perPage);
266
+        }
267
+
243 268
 
244 269
 
245 270
         public LuResult<T> Edit<T>(Expression<Func<TModel, bool>> predicate, Action<TModel> update,

+ 17
- 0
Luticate2.Utils/DataAccess/Npgsql/ExpressionVisitorDebugger.cs Voir le fichier

@@ -0,0 +1,17 @@
1
+using System.Linq.Expressions;
2
+
3
+namespace Luticate2.Utils.DataAccess.Npgsql
4
+{
5
+    public class ExpressionVisitorDebugger : ExpressionVisitor
6
+    {
7
+        protected override Expression VisitUnary(UnaryExpression node)
8
+        {
9
+            return base.VisitUnary(node);
10
+        }
11
+
12
+        protected override Expression VisitBinary(BinaryExpression node)
13
+        {
14
+            return base.VisitBinary(node);
15
+        }
16
+    }
17
+}

+ 19
- 0
Luticate2.Utils/DataAccess/Npgsql/NpgsqlCompositeMethodCallTranslatorLuticate.cs Voir le fichier

@@ -0,0 +1,19 @@
1
+using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators;
2
+using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators.Internal;
3
+using Microsoft.Extensions.Logging;
4
+
5
+namespace Luticate2.Utils.DataAccess.Npgsql
6
+{
7
+    public class NpgsqlCompositeMethodCallTranslatorLuticate : NpgsqlCompositeMethodCallTranslator
8
+    {
9
+        private static readonly IMethodCallTranslator[] _methodCallTranslators2 =
10
+        {
11
+            new NpgsqlIntToStringTranslator()
12
+        };
13
+
14
+        public NpgsqlCompositeMethodCallTranslatorLuticate(ILogger<NpgsqlCompositeMethodCallTranslator> logger) : base(logger)
15
+        {
16
+            AddTranslators(_methodCallTranslators2);
17
+        }
18
+    }
19
+}

+ 31
- 0
Luticate2.Utils/DataAccess/Npgsql/NpgsqlIntToStringTranslator.cs Voir le fichier

@@ -0,0 +1,31 @@
1
+using System;
2
+using System.Linq;
3
+using System.Linq.Expressions;
4
+using System.Reflection;
5
+using Microsoft.EntityFrameworkCore.Query.Expressions;
6
+using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators;
7
+
8
+namespace Luticate2.Utils.DataAccess.Npgsql
9
+{
10
+    public class NpgsqlIntToStringTranslator : IMethodCallTranslator
11
+    {
12
+        private readonly Type[] _declaringTypes = {typeof(int), typeof(int?)};
13
+
14
+        private readonly string _clrMethodName = "ToString";
15
+
16
+        public Expression Translate(MethodCallExpression methodCallExpression)
17
+        {
18
+            foreach (var declaringType in _declaringTypes)
19
+            {
20
+                var methodInfo = declaringType.GetTypeInfo()
21
+                    .GetDeclaredMethods(_clrMethodName).SingleOrDefault(m => !m.GetParameters().Any());
22
+                if (methodInfo != null && declaringType.IsAssignableFrom(methodCallExpression.Object.Type))
23
+                {
24
+                    return new ExplicitCastExpression(methodCallExpression.Object, typeof(string));
25
+                }
26
+            }
27
+
28
+            return null;
29
+        }
30
+    }
31
+}

+ 50
- 0
Luticate2.Utils/Dbo/Filter/LuFilterBinder.cs Voir le fichier

@@ -0,0 +1,50 @@
1
+using System.Threading.Tasks;
2
+using Luticate2.Utils.Dbo.Result;
3
+using Microsoft.AspNetCore.Mvc.ModelBinding;
4
+
5
+namespace Luticate2.Utils.Dbo.Filter
6
+{
7
+    public class LuFilterBinder : IModelBinder
8
+    {
9
+        public static LuResult<LuFilterDbo> FromString(string data)
10
+        {
11
+            if (data == null)
12
+            {
13
+                data = "";
14
+            }
15
+            data = data.Trim();
16
+            var dbo = new LuFilterDbo
17
+            {
18
+                Query = data
19
+            };
20
+            return LuResult<LuFilterDbo>.Ok(dbo);
21
+        }
22
+
23
+        public Task BindModelAsync(ModelBindingContext bindingContext)
24
+        {
25
+            var messageTypeResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
26
+            var res = FromString(messageTypeResult.FirstValue);
27
+            if (res)
28
+            {
29
+                bindingContext.Result = ModelBindingResult.Success(res.Data);
30
+            }
31
+            else
32
+            {
33
+                bindingContext.Result = ModelBindingResult.Failed();
34
+            }
35
+            return Task.FromResult(0);
36
+        }
37
+    }
38
+
39
+    public class LuFilterBinderProvider : IModelBinderProvider
40
+    {
41
+        public IModelBinder GetBinder(ModelBinderProviderContext context)
42
+        {
43
+            if (context.Metadata.ModelType == typeof(LuFilterDbo))
44
+            {
45
+                return new LuFilterBinder();
46
+            }
47
+            return null;
48
+        }
49
+    }
50
+}

+ 1
- 1
Luticate2.Utils/Dbo/Filter/LuFilterDbo.cs Voir le fichier

@@ -2,6 +2,6 @@
2 2
 {
3 3
     public class LuFilterDbo
4 4
     {
5
-
5
+        public string Query { get; set; }
6 6
     }
7 7
 }

+ 4
- 0
Luticate2.Utils/Interfaces/ILuCrudInterface.cs Voir le fichier

@@ -2,6 +2,7 @@
2 2
 using System.Collections.Generic;
3 3
 using Luticate2.Utils.Dbo;
4 4
 using Luticate2.Utils.Dbo.Basic;
5
+using Luticate2.Utils.Dbo.Filter;
5 6
 using Luticate2.Utils.Dbo.OrderBy;
6 7
 using Luticate2.Utils.Dbo.Result;
7 8
 
@@ -38,6 +39,9 @@ namespace Luticate2.Utils.Interfaces
38 39
         LuResult<TDboRead> GetSingleById(long id);
39 40
 
40 41
 
42
+        LuResult<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, LuFilterDbo filter,
43
+            int page = 0, int perPage = int.MaxValue);
44
+
41 45
         LuResult<LuPaginatedDbo<TDboRead>> GetMultiple(LuOrderByDbo orderBy, int page = 0, int perPage = int.MaxValue);
42 46
 
43 47
 

+ 11
- 0
Test/Utils/DataAccess/LuUtilsPartialContext.cs Voir le fichier

@@ -0,0 +1,11 @@
1
+using System;
2
+using Microsoft.EntityFrameworkCore;
3
+using Luticate2.Auth.DataAccess.Models;
4
+using Test.Utils.DataAccess.Models;
5
+
6
+namespace Test.Utils.DataAccess
7
+{
8
+    public partial class LuUtilsDbContext
9
+    {
10
+    }
11
+}

+ 10
- 1
Test/Utils/DataAccess/LuUtilsPkBigSerialDataAccess.cs Voir le fichier

@@ -1,4 +1,7 @@
1
-using Luticate2.Utils.DataAccess;
1
+using System;
2
+using System.Linq.Expressions;
3
+using Luticate2.Utils.DataAccess;
4
+using Luticate2.Utils.Dbo.Filter;
2 5
 using Test.Utils.DataAccess.Models;
3 6
 using Test.Utils.Dbo.PkBigSerial;
4 7
 
@@ -31,5 +34,11 @@ namespace Test.Utils.DataAccess
31 34
                 SomeText = model.some_text
32 35
             };
33 36
         }
37
+
38
+        protected override Expression<Func<pk_bigserial, bool>> GetFilterExpression(LuFilterDbo filter)
39
+        {
40
+            var query = filter.Query.ToLower();
41
+            return model => model.some_text.ToLower().Contains(query) || model.some_int.ToString().Contains(query);
42
+        }
34 43
     }
35 44
 }

+ 10
- 1
Test/Utils/DataAccess/LuUtilsPkGuidDataAccess.cs Voir le fichier

@@ -1,4 +1,7 @@
1
-using Luticate2.Utils.DataAccess;
1
+using System;
2
+using System.Linq.Expressions;
3
+using Luticate2.Utils.DataAccess;
4
+using Luticate2.Utils.Dbo.Filter;
2 5
 using Test.Utils.DataAccess.Models;
3 6
 using Test.Utils.Dbo.PkGuid;
4 7
 
@@ -32,5 +35,11 @@ namespace Test.Utils.DataAccess
32 35
                 SomeText = model.some_text
33 36
             };
34 37
         }
38
+
39
+        protected override Expression<Func<pk_guid, bool>> GetFilterExpression(LuFilterDbo filter)
40
+        {
41
+            var query = filter.Query.ToLower();
42
+            return model => model.some_text.ToLower().Contains(query) || model.some_int.ToString().Contains(query);
43
+        }
35 44
     }
36 45
 }

+ 9
- 1
WebTest/Startup.cs Voir le fichier

@@ -1,4 +1,5 @@
1 1
 using Luticate2.Auth.Controllers;
2
+using Luticate2.Utils.Controllers;
2 3
 using Microsoft.AspNetCore.Builder;
3 4
 using Microsoft.AspNetCore.Hosting;
4 5
 using Microsoft.EntityFrameworkCore;
@@ -42,7 +43,14 @@ namespace WebTest
42 43
 
43 44
             services.AddTransient<PkGuidBusiness>();
44 45
             services.AddTransient<LuUtilsPkGuidDataAccess>();
45
-            services.AddDbContext<LuUtilsDbContext>(options => options.UseNpgsql(Tests.ConnectionString));
46
+            services.AddDbContext<LuUtilsDbContext>(options =>
47
+            {
48
+                options.UseNpgsql(Tests.ConnectionString);
49
+                options.UseInternalServiceProvider(new ServiceCollection()
50
+                    .AddEntityFrameworkNpgsqlLuticate()
51
+                    .AddEntityFrameworkNpgsql()
52
+                    .BuildServiceProvider());
53
+            });
46 54
 
47 55
             services.AddMvc()
48 56
                 .AddLuticateAuth();

Chargement…
Annuler
Enregistrer