@@ -113,24 +113,44 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
113
113
114
114
var concreteType = typeof ( TSource ) ;
115
115
var property = concreteType . GetProperty ( filterQuery . FilteredAttribute . InternalAttributeName ) ;
116
+ var op = filterQuery . FilterOperation ;
116
117
117
118
if ( property == null )
118
119
throw new ArgumentException ( $ "'{ filterQuery . FilteredAttribute . InternalAttributeName } ' is not a valid property of '{ concreteType } '") ;
119
120
120
121
try
121
122
{
122
- if ( filterQuery . FilterOperation == FilterOperations . @in || filterQuery . FilterOperation == FilterOperations . nin )
123
+ if ( op == FilterOperations . @in || op == FilterOperations . nin )
123
124
{
124
125
string [ ] propertyValues = filterQuery . PropertyValue . Split ( ',' ) ;
125
- var lambdaIn = ArrayContainsPredicate < TSource > ( propertyValues , property . Name , filterQuery . FilterOperation ) ;
126
+ var lambdaIn = ArrayContainsPredicate < TSource > ( propertyValues , property . Name , op ) ;
126
127
127
128
return source . Where ( lambdaIn ) ;
128
129
}
130
+ else if ( op == FilterOperations . @is || op == FilterOperations . isnot ) {
131
+ var parameter = Expression . Parameter ( concreteType , "model" ) ;
132
+ // {model.Id}
133
+ var left = Expression . PropertyOrField ( parameter , property . Name ) ;
134
+ var right = Expression . Constant ( filterQuery . PropertyValue , typeof ( string ) ) ;
135
+
136
+ var body = GetFilterExpressionLambda ( left , right , op ) ;
137
+ var lambda = Expression . Lambda < Func < TSource , bool > > ( body , parameter ) ;
138
+
139
+ return source . Where ( lambda ) ;
140
+ }
129
141
else
130
142
{
131
143
var isNullabe = IsNullable ( property . PropertyType ) ;
132
144
var propertyValue = filterQuery . PropertyValue ;
133
- var value = isNullabe && propertyValue == "" ? null : propertyValue ;
145
+ var value = propertyValue ;
146
+
147
+ if ( op == FilterOperations . @isnot || op == FilterOperations . isnot )
148
+ {
149
+ if ( isNullabe && propertyValue == "null" )
150
+ {
151
+ value = null ;
152
+ }
153
+ }
134
154
135
155
// convert the incoming value to the target value type
136
156
// "1" -> 1
@@ -142,7 +162,7 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
142
162
// {1}
143
163
var right = Expression . Constant ( convertedValue , property . PropertyType ) ;
144
164
145
- var body = GetFilterExpressionLambda ( left , right , filterQuery . FilterOperation ) ;
165
+ var body = GetFilterExpressionLambda ( left , right , op ) ;
146
166
147
167
var lambda = Expression . Lambda < Func < TSource , bool > > ( body , parameter ) ;
148
168
@@ -244,6 +264,14 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression
244
264
case FilterOperations . ne :
245
265
body = Expression . NotEqual ( left , right ) ;
246
266
break ;
267
+ case FilterOperations . isnot :
268
+ // {model.Id != null}
269
+ body = Expression . NotEqual ( left , right ) ;
270
+ break ;
271
+ case FilterOperations . @is :
272
+ // {model.Id == null}
273
+ body = Expression . Equal ( left , right ) ;
274
+ break ;
247
275
default :
248
276
throw new JsonApiException ( 500 , $ "Unknown filter operation { operation } ") ;
249
277
}
0 commit comments