Skip to content

Commit 676b654

Browse files
Sergey Koshelmaurei
Sergey Koshel
authored andcommitted
Added value types support to the filters isnull & isnotnull. (#549)
1 parent cc46a60 commit 676b654

File tree

2 files changed

+80
-2
lines changed

2 files changed

+80
-2
lines changed

src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs

+20-2
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,29 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression
170170
break;
171171
case FilterOperations.isnotnull:
172172
// {model.Id != null}
173-
body = Expression.NotEqual(left, right);
173+
if (left.Type.IsValueType &&
174+
!(left.Type.IsGenericType && left.Type.GetGenericTypeDefinition() == typeof(Nullable<>)))
175+
{
176+
var nullableType = typeof(Nullable<>).MakeGenericType(left.Type);
177+
body = Expression.NotEqual(Expression.Convert(left, nullableType), right);
178+
}
179+
else
180+
{
181+
body = Expression.NotEqual(left, right);
182+
}
174183
break;
175184
case FilterOperations.isnull:
176185
// {model.Id == null}
177-
body = Expression.Equal(left, right);
186+
if (left.Type.IsValueType &&
187+
!(left.Type.IsGenericType && left.Type.GetGenericTypeDefinition() == typeof(Nullable<>)))
188+
{
189+
var nullableType = typeof(Nullable<>).MakeGenericType(left.Type);
190+
body = Expression.Equal(Expression.Convert(left, nullableType), right);
191+
}
192+
else
193+
{
194+
body = Expression.Equal(left, right);
195+
}
178196
break;
179197
default:
180198
throw new JsonApiException(500, $"Unknown filter operation {operation}");

test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs

+60
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,36 @@ public async Task Can_Filter_TodoItems_Using_IsNotNull_Operator()
175175
Assert.All(todoItems, t => Assert.NotNull(t.UpdatedDate));
176176
}
177177

178+
[Fact]
179+
public async Task Can_Filter_TodoItems_ByParent_Using_IsNotNull_Operator()
180+
{
181+
// Arrange
182+
var todoItem = _todoItemFaker.Generate();
183+
todoItem.Assignee = new Person();
184+
185+
var otherTodoItem = _todoItemFaker.Generate();
186+
otherTodoItem.Assignee = null;
187+
188+
_context.TodoItems.AddRange(new[] { todoItem, otherTodoItem });
189+
_context.SaveChanges();
190+
191+
var httpMethod = new HttpMethod("GET");
192+
var route = $"/api/v1/todo-items?filter[assignee.id]=isnotnull:";
193+
var request = new HttpRequestMessage(httpMethod, route);
194+
195+
// Act
196+
var response = await _fixture.Client.SendAsync(request);
197+
198+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
199+
200+
var body = await response.Content.ReadAsStringAsync();
201+
var todoItems = _fixture.GetService<IJsonApiDeSerializer>().DeserializeList<TodoItem>(body);
202+
203+
// Assert
204+
Assert.NotEmpty(todoItems);
205+
Assert.All(todoItems, t => Assert.NotNull(t.Assignee));
206+
}
207+
178208
[Fact]
179209
public async Task Can_Filter_TodoItems_Using_IsNull_Operator()
180210
{
@@ -205,6 +235,36 @@ public async Task Can_Filter_TodoItems_Using_IsNull_Operator()
205235
Assert.All(todoItems, t => Assert.Null(t.UpdatedDate));
206236
}
207237

238+
[Fact]
239+
public async Task Can_Filter_TodoItems_ByParent_Using_IsNull_Operator()
240+
{
241+
// Arrange
242+
var todoItem = _todoItemFaker.Generate();
243+
todoItem.Assignee = null;
244+
245+
var otherTodoItem = _todoItemFaker.Generate();
246+
otherTodoItem.Assignee = new Person();
247+
248+
_context.TodoItems.AddRange(new[] { todoItem, otherTodoItem });
249+
_context.SaveChanges();
250+
251+
var httpMethod = new HttpMethod("GET");
252+
var route = $"/api/v1/todo-items?filter[assignee.id]=isnull:";
253+
var request = new HttpRequestMessage(httpMethod, route);
254+
255+
// Act
256+
var response = await _fixture.Client.SendAsync(request);
257+
258+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
259+
260+
var body = await response.Content.ReadAsStringAsync();
261+
var todoItems = _fixture.GetService<IJsonApiDeSerializer>().DeserializeList<TodoItem>(body);
262+
263+
// Assert
264+
Assert.NotEmpty(todoItems);
265+
Assert.All(todoItems, t => Assert.Null(t.Assignee));
266+
}
267+
208268
[Fact]
209269
public async Task Can_Filter_TodoItems_Using_Like_Operator()
210270
{

0 commit comments

Comments
 (0)