Skip to content

Commit b2d73c5

Browse files
Code refactor.
1 parent ba07678 commit b2d73c5

File tree

3 files changed

+72
-10
lines changed

3 files changed

+72
-10
lines changed

src/CouchDB.Driver/CouchQueryProvider.cs

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using CouchDB.Driver.Types;
55
using Flurl.Http;
66
using System;
7+
using System.Collections.Generic;
78
using System.Linq;
89
using System.Linq.Expressions;
910
using System.Reflection;
@@ -32,21 +33,40 @@ public override string GetQueryText(Expression expression)
3233

3334
public override object Execute(Expression e, bool completeResponse)
3435
{
36+
MethodInfo _filterMethodInfo = null;
37+
Expression[] _filteringExpressions = Array.Empty<Expression>();
38+
if (e is MethodCallExpression m)
39+
{
40+
if (
41+
m.Method.Name == "First" ||
42+
m.Method.Name == "FirstOrDefault" ||
43+
m.Method.Name == "Last" ||
44+
m.Method.Name == "LastOrDefault" ||
45+
m.Method.Name == "Single" ||
46+
m.Method.Name == "SingleOrDefault")
47+
{
48+
_filterMethodInfo = m.Method;
49+
_filteringExpressions = m.Arguments.Skip(1).ToArray();
50+
e = m.Arguments[0];
51+
}
52+
}
53+
3554
var body = Translate(e);
3655
Type elementType = TypeSystem.GetElementType(e.Type);
3756

38-
MethodInfo method = typeof(CouchQueryProvider).GetMethod("GetCouchList");
57+
MethodInfo method = typeof(CouchQueryProvider).GetMethod(nameof(CouchQueryProvider.GetCouchListOrFiltered));
3958
MethodInfo generic = method.MakeGenericMethod(elementType);
40-
return generic.Invoke(this, new[] { body });
59+
var result = generic.Invoke(this, new[] { body, (object)_filterMethodInfo, _filteringExpressions });
60+
return result;
4161
}
42-
62+
4363
private string Translate(Expression expression)
4464
{
4565
expression = Evaluator.PartialEval(expression);
4666
return new QueryTranslator(_settings).Translate(expression);
4767
}
4868

49-
public CouchList<T> GetCouchList<T>(string body)
69+
public object GetCouchListOrFiltered<T>(string body, MethodInfo filteringMethodInfo, Expression[] filteringExpressions)
5070
{
5171
FindResult<T> result = _flurlClient
5272
.Request(_connectionString)
@@ -56,7 +76,49 @@ public CouchList<T> GetCouchList<T>(string body)
5676
.SendRequest();
5777

5878
var couchList = new CouchList<T>(result.Docs.ToList(), result.Bookmark, result.ExecutionStats);
59-
return couchList;
79+
80+
if (filteringMethodInfo == null)
81+
{
82+
return couchList;
83+
}
84+
85+
var filteringMethods = typeof(Enumerable).GetMethods()
86+
.Where(m =>
87+
m.Name == filteringMethodInfo.Name &&
88+
m.GetParameters().Length - 1 == filteringExpressions.Length)
89+
.OrderBy(m => m.GetParameters().Length).ToList();
90+
91+
92+
var invokeParameter = new object[filteringExpressions.Length + 1];
93+
invokeParameter[0] = couchList;
94+
95+
bool IsRightOverload(MethodInfo m)
96+
{
97+
ParameterInfo[] parameters = m.GetParameters();
98+
for (var i = 0; i < filteringExpressions.Length; i++)
99+
{
100+
var lamdaExpression = filteringExpressions[i] as UnaryExpression;
101+
if (lamdaExpression == null)
102+
{
103+
return false;
104+
}
105+
106+
if (lamdaExpression.Operand.Type != parameters[i + 1].ParameterType)
107+
{
108+
return false;
109+
}
110+
invokeParameter[i + 1] = lamdaExpression.Operand;
111+
}
112+
return true;
113+
}
114+
115+
MethodInfo rightOverload = filteringMethods.Single(IsRightOverload);
116+
117+
MethodInfo enumerableGenericFilteringMethod = rightOverload.MakeGenericMethod(typeof(T));
118+
119+
120+
var filtered = enumerableGenericFilteringMethod.Invoke(null, invokeParameter);
121+
return filtered;
60122
}
61123
}
62124
}

src/CouchDB.Driver/QueryTranslator.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
using CouchDB.Driver.Settings;
22
using System;
33
using System.Linq.Expressions;
4+
using System.Reflection;
45
using System.Text;
56

67
namespace CouchDB.Driver
7-
{
8+
{
89
internal partial class QueryTranslator : ExpressionVisitor
910
{
1011
private readonly CouchSettings _settings;
@@ -20,7 +21,7 @@ internal string Translate(Expression expression)
2021
_sb = new StringBuilder();
2122
_sb.Append("{");
2223
Visit(expression);
23-
24+
2425
// If no Where() calls
2526
if (!_isSelectorSet)
2627
{

src/CouchDB.Driver/Translators/MethodCallExpressionTranslator.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
using CouchDB.Driver.Extensions;
22
using CouchDB.Driver.Types;
3-
using Newtonsoft.Json;
43
using System;
54
using System.Collections.Generic;
65
using System.Linq;
76
using System.Linq.Expressions;
87

8+
#pragma warning disable IDE0058 // Expression value is never used
99
namespace CouchDB.Driver
1010
{
11-
#pragma warning disable IDE0058 // Expression value is never used
1211
internal partial class QueryTranslator
1312
{
1413
private static Expression StripQuotes(Expression e)
@@ -443,5 +442,5 @@ private Expression VisitContainsMethod(MethodCallExpression m)
443442

444443
#endregion
445444
}
446-
#pragma warning restore IDE0058 // Expression value is never used
447445
}
446+
#pragma warning restore IDE0058 // Expression value is never used

0 commit comments

Comments
 (0)