diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 73e3a14a3e..79eda6c598 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -195,6 +195,10 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression case FilterOperations.like: body = Expression.Call(left, "Contains", null, right); break; + // {model.Id != 1} + case FilterOperations.ne: + body = Expression.NotEqual(left, right); + break; default: throw new JsonApiException(500, $"Unknown filter operation {operation}"); } diff --git a/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs b/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs index 260dc32655..e3c207ce47 100644 --- a/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs +++ b/src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs @@ -8,6 +8,7 @@ public enum FilterOperations gt = 2, le = 3, ge = 4, - like = 5 + like = 5, + ne = 6 } -} \ No newline at end of file +} diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs index 083b2c22d7..b84b57e31b 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -105,5 +105,31 @@ public async Task Cannot_Filter_If_Explicitly_Forbidden() // assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } + + [Fact] + public async Task Can_Filter_On_Not_Equal_Values() + { + // arrange + var context = _fixture.GetService(); + var todoItem = _todoItemFaker.Generate(); + context.TodoItems.Add(todoItem); + await context.SaveChangesAsync(); + + var totalCount = context.TodoItems.Count(); + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?page[size]={totalCount}&filter[ordinal]=ne:{todoItem.Ordinal}"; + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await _fixture.Client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + var deserializedTodoItems = _fixture + .GetService() + .DeserializeList(body); + + // assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.False(deserializedTodoItems.Any(i => i.Ordinal == todoItem.Ordinal)); + } } }