2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
4
using System . Linq . Expressions ;
5
+ using System . Reflection ;
5
6
using JsonApiDotNetCore . Internal ;
6
7
using JsonApiDotNetCore . Internal . Query ;
7
8
using JsonApiDotNetCore . Services ;
@@ -11,6 +12,23 @@ namespace JsonApiDotNetCore.Extensions
11
12
// ReSharper disable once InconsistentNaming
12
13
public static class IQueryableExtensions
13
14
{
15
+ private static MethodInfo _containsMethod ;
16
+ private static MethodInfo ContainsMethod
17
+ {
18
+ get
19
+ {
20
+ if ( _containsMethod == null )
21
+ {
22
+ _containsMethod = typeof ( Enumerable )
23
+ . GetMethods ( BindingFlags . Static | BindingFlags . Public )
24
+ . Where ( m => m . Name == nameof ( Enumerable . Contains ) && m . GetParameters ( ) . Count ( ) == 2 )
25
+ . First ( ) ;
26
+ }
27
+ return _containsMethod ;
28
+ }
29
+ }
30
+
31
+
14
32
public static IQueryable < TSource > Sort < TSource > ( this IQueryable < TSource > source , List < SortQuery > sortQueries )
15
33
{
16
34
if ( sortQueries == null || sortQueries . Count == 0 )
@@ -101,21 +119,30 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
101
119
102
120
try
103
121
{
104
- // convert the incoming value to the target value type
105
- // "1" -> 1
106
- var convertedValue = TypeHelper . ConvertType ( filterQuery . PropertyValue , property . PropertyType ) ;
107
- // {model}
108
- var parameter = Expression . Parameter ( concreteType , "model" ) ;
109
- // {model.Id}
110
- var left = Expression . PropertyOrField ( parameter , property . Name ) ;
111
- // {1}
112
- var right = Expression . Constant ( convertedValue , property . PropertyType ) ;
113
-
114
- var body = GetFilterExpressionLambda ( left , right , filterQuery . FilterOperation ) ;
115
-
116
- var lambda = Expression . Lambda < Func < TSource , bool > > ( body , parameter ) ;
117
-
118
- return source . Where ( lambda ) ;
122
+ if ( filterQuery . FilterOperation == FilterOperations . @in )
123
+ {
124
+ string [ ] propertyValues = filterQuery . PropertyValue . Split ( ',' ) ;
125
+ var lambdaIn = ArrayContainsPredicate < TSource > ( propertyValues , property . Name ) ;
126
+
127
+ return source . Where ( lambdaIn ) ;
128
+ }
129
+ else
130
+ { // convert the incoming value to the target value type
131
+ // "1" -> 1
132
+ var convertedValue = TypeHelper . ConvertType ( filterQuery . PropertyValue , property . PropertyType ) ;
133
+ // {model}
134
+ var parameter = Expression . Parameter ( concreteType , "model" ) ;
135
+ // {model.Id}
136
+ var left = Expression . PropertyOrField ( parameter , property . Name ) ;
137
+ // {1}
138
+ var right = Expression . Constant ( convertedValue , property . PropertyType ) ;
139
+
140
+ var body = GetFilterExpressionLambda ( left , right , filterQuery . FilterOperation ) ;
141
+
142
+ var lambda = Expression . Lambda < Func < TSource , bool > > ( body , parameter ) ;
143
+
144
+ return source . Where ( lambda ) ;
145
+ }
119
146
}
120
147
catch ( FormatException )
121
148
{
@@ -140,26 +167,36 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
140
167
141
168
try
142
169
{
143
- // convert the incoming value to the target value type
144
- // "1" -> 1
145
- var convertedValue = TypeHelper . ConvertType ( filterQuery . PropertyValue , relatedAttr . PropertyType ) ;
146
- // {model}
147
- var parameter = Expression . Parameter ( concreteType , "model" ) ;
170
+ if ( filterQuery . FilterOperation == FilterOperations . @in )
171
+ {
172
+ string [ ] propertyValues = filterQuery . PropertyValue . Split ( ',' ) ;
173
+ var lambdaIn = ArrayContainsPredicate < TSource > ( propertyValues , relatedAttr . Name , relation . Name ) ;
148
174
149
- // {model.Relationship}
150
- var leftRelationship = Expression . PropertyOrField ( parameter , relation . Name ) ;
175
+ return source . Where ( lambdaIn ) ;
176
+ }
177
+ else
178
+ {
179
+ // convert the incoming value to the target value type
180
+ // "1" -> 1
181
+ var convertedValue = TypeHelper . ConvertType ( filterQuery . PropertyValue , relatedAttr . PropertyType ) ;
182
+ // {model}
183
+ var parameter = Expression . Parameter ( concreteType , "model" ) ;
151
184
152
- // {model.Relationship.Attr }
153
- var left = Expression . PropertyOrField ( leftRelationship , relatedAttr . Name ) ;
185
+ // {model.Relationship}
186
+ var leftRelationship = Expression . PropertyOrField ( parameter , relation . Name ) ;
154
187
155
- // {1 }
156
- var right = Expression . Constant ( convertedValue , relatedAttr . PropertyType ) ;
188
+ // {model.Relationship.Attr }
189
+ var left = Expression . PropertyOrField ( leftRelationship , relatedAttr . Name ) ;
157
190
158
- var body = GetFilterExpressionLambda ( left , right , filterQuery . FilterOperation ) ;
191
+ // {1}
192
+ var right = Expression . Constant ( convertedValue , relatedAttr . PropertyType ) ;
159
193
160
- var lambda = Expression . Lambda < Func < TSource , bool > > ( body , parameter ) ;
194
+ var body = GetFilterExpressionLambda ( left , right , filterQuery . FilterOperation ) ;
161
195
162
- return source . Where ( lambda ) ;
196
+ var lambda = Expression . Lambda < Func < TSource , bool > > ( body , parameter ) ;
197
+
198
+ return source . Where ( lambda ) ;
199
+ }
163
200
}
164
201
catch ( FormatException )
165
202
{
@@ -206,6 +243,25 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression
206
243
return body ;
207
244
}
208
245
246
+ private static Expression < Func < TSource , bool > > ArrayContainsPredicate < TSource > ( string [ ] propertyValues , string fieldname , string relationName = null )
247
+ {
248
+ ParameterExpression entity = Expression . Parameter ( typeof ( TSource ) , "entity" ) ;
249
+ MemberExpression member ;
250
+ if ( ! string . IsNullOrEmpty ( relationName ) )
251
+ {
252
+ var relation = Expression . PropertyOrField ( entity , relationName ) ;
253
+ member = Expression . Property ( relation , fieldname ) ;
254
+ }
255
+ else
256
+ member = Expression . Property ( entity , fieldname ) ;
257
+
258
+ var method = ContainsMethod . MakeGenericMethod ( member . Type ) ;
259
+ var obj = TypeHelper . ConvertListType ( propertyValues , member . Type ) ;
260
+
261
+ var exprContains = Expression . Call ( method , new Expression [ ] { Expression . Constant ( obj ) , member } ) ;
262
+ return Expression . Lambda < Func < TSource , bool > > ( exprContains , entity ) ;
263
+ }
264
+
209
265
public static IQueryable < TSource > Select < TSource > ( this IQueryable < TSource > source , List < string > columns )
210
266
{
211
267
if ( columns == null || columns . Count == 0 )
0 commit comments