Skip to content

Commit ce76217

Browse files
authored
Merge pull request #45 from Research-Institute/like-filter
Like filter
2 parents b247d15 + 835f12b commit ce76217

File tree

5 files changed

+51
-10
lines changed

5 files changed

+51
-10
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ identifier):
285285
?filter[attribute]=gt:value
286286
?filter[attribute]=le:value
287287
?filter[attribute]=ge:value
288+
?filter[attribute]=like:value
288289
```
289290

290291
### Sorting

src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
8686
// {1}
8787
var right = Expression.Constant(convertedValue, property.PropertyType);
8888

89-
var body = Expression.Equal(left, right);
89+
Expression body;
9090
switch (filterQuery.FilterOperation)
9191
{
9292
case FilterOperations.eq:
@@ -109,6 +109,12 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
109109
// {model.Id <= 1}
110110
body = Expression.GreaterThanOrEqual(left, right);
111111
break;
112+
case FilterOperations.like:
113+
// {model.Id <= 1}
114+
body = Expression.Call(left, "Contains", null, right);
115+
break;
116+
default:
117+
throw new JsonApiException("500", $"Unknown filter operation {filterQuery.FilterOperation}");
112118
}
113119

114120
var lambda = Expression.Lambda<Func<TSource, bool>>(body, parameter);

src/JsonApiDotNetCore/Internal/Query/FilterOperations.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public enum FilterOperations
66
lt = 1,
77
gt = 2,
88
le = 3,
9-
ge = 4
9+
ge = 4,
10+
like = 5
1011
}
1112
}

src/JsonApiDotNetCore/Internal/Query/QuerySet.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,29 @@ private FilterQuery ParseFilterOperation(AttrAttribute attribute, string value)
8383
if(value.Length < 3)
8484
return new FilterQuery(attribute, value, FilterOperations.eq);
8585

86-
var prefix = value.Substring(0, 3);
86+
var operation = value.Split(':');
8787

88-
if(prefix[2] != ':')
88+
if(operation.Length == 1)
8989
return new FilterQuery(attribute, value, FilterOperations.eq);
9090

9191
// remove prefix from value
92-
value = value.Substring(3, value.Length - 3);
92+
var prefix = operation[0];
93+
value = operation[1];
9394

9495
switch(prefix)
9596
{
96-
case "eq:":
97+
case "eq":
9798
return new FilterQuery(attribute, value, FilterOperations.eq);
98-
case "lt:":
99+
case "lt":
99100
return new FilterQuery(attribute, value, FilterOperations.lt);
100-
case "gt:":
101+
case "gt":
101102
return new FilterQuery(attribute, value, FilterOperations.gt);
102-
case "le:":
103+
case "le":
103104
return new FilterQuery(attribute, value, FilterOperations.le);
104-
case "ge:":
105+
case "ge":
105106
return new FilterQuery(attribute, value, FilterOperations.ge);
107+
case "like":
108+
return new FilterQuery(attribute, value, FilterOperations.like);
106109
}
107110

108111
throw new JsonApiException("400", $"Invalid filter prefix '{prefix}'");

test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,36 @@ public async Task Can_Filter_TodoItems()
124124
Assert.Equal(todoItem.Ordinal, todoItemResult.Ordinal);
125125
}
126126

127+
[Fact]
128+
public async Task Can_Filter_TodoItems_Using_Like_Operator()
129+
{
130+
// Arrange
131+
var todoItem = _todoItemFaker.Generate();
132+
todoItem.Ordinal = 999999;
133+
_context.TodoItems.Add(todoItem);
134+
_context.SaveChanges();
135+
var substring = todoItem.Description.Substring(1, todoItem.Description.Length - 2);
136+
137+
var httpMethod = new HttpMethod("GET");
138+
var route = $"/api/v1/todo-items?filter[description]=like:{substring}";
139+
140+
var description = new RequestProperties("Filter TodoItems Where Attribute Like", new Dictionary<string, string> {
141+
{ "?filter[...]=", "Filter on attribute" }
142+
});
143+
144+
// Act
145+
var response = await _fixture.MakeRequest<TodoItem>(description, httpMethod, route);
146+
var body = await response.Content.ReadAsStringAsync();
147+
var deserializedBody = JsonApiDeSerializer.DeserializeList<TodoItem>(body, _jsonApiContext);
148+
149+
// Assert
150+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
151+
Assert.NotEmpty(deserializedBody);
152+
153+
foreach (var todoItemResult in deserializedBody)
154+
Assert.Contains(substring, todoItem.Description);
155+
}
156+
127157
[Fact]
128158
public async Task Can_Sort_TodoItems_By_Ordinal_Ascending()
129159
{

0 commit comments

Comments
 (0)