Skip to content

Commit 5717f30

Browse files
committed
Pass FilterQuery to GetQueryFilters
1 parent 11fe0da commit 5717f30

File tree

4 files changed

+109
-2
lines changed

4 files changed

+109
-2
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,33 @@
11
using System.Collections.Generic;
2+
using System.Linq;
23
using JsonApiDotNetCore.Models;
34
using JsonApiDotNetCoreExample.Models;
5+
using JsonApiDotNetCore.Internal.Query;
46

57
namespace JsonApiDotNetCoreExample.Resources
68
{
79
public class UserResource : ResourceDefinition<User>
810
{
911
protected override List<AttrAttribute> OutputAttrs()
1012
=> Remove(user => user.Password);
13+
14+
public override QueryFilters GetQueryFilters()
15+
{
16+
return new QueryFilters
17+
{
18+
{ "first-character", (users, queryFilter) => FirstCharacterFilter(users, queryFilter) }
19+
};
20+
}
21+
22+
private IQueryable<User> FirstCharacterFilter(IQueryable<User> users, FilterQuery filterQuery)
23+
{
24+
switch(filterQuery.Operation)
25+
{
26+
case "lt":
27+
return users.Where(u => u.Username[0] < filterQuery.Value[0]);
28+
default:
29+
return users.Where(u => u.Username[0] == filterQuery.Value[0]);
30+
}
31+
}
1132
}
1233
}

src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public virtual IQueryable<TEntity> Filter(IQueryable<TEntity> entities, FilterQu
108108
var defaultQueryFilters = _resourceDefinition.GetQueryFilters();
109109
if (defaultQueryFilters != null && defaultQueryFilters.TryGetValue(filterQuery.Attribute, out var defaultQueryFilter) == true)
110110
{
111-
return defaultQueryFilter(entities, filterQuery.Value);
111+
return defaultQueryFilter(entities, filterQuery);
112112
}
113113
}
114114

src/JsonApiDotNetCore/Models/ResourceDefinition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private List<AttrAttribute> GetOutputAttrs()
162162
/// method signature.
163163
/// See <see cref="GetQueryFilters" /> for usage details.
164164
/// </summary>
165-
public class QueryFilters : Dictionary<string, Func<IQueryable<T>, string, IQueryable<T>>> { }
165+
public class QueryFilters : Dictionary<string, Func<IQueryable<T>, FilterQuery, IQueryable<T>>> { }
166166

167167
/// <summary>
168168
/// Define a the default sort order if no sort key is provided.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Net;
4+
using System.Net.Http;
5+
using System.Net.Http.Headers;
6+
using System.Threading.Tasks;
7+
using Bogus;
8+
using JsonApiDotNetCore.Models;
9+
using JsonApiDotNetCore.Serialization;
10+
using JsonApiDotNetCoreExample.Data;
11+
using JsonApiDotNetCoreExample.Models;
12+
using Microsoft.EntityFrameworkCore;
13+
using Newtonsoft.Json;
14+
using Xunit;
15+
16+
namespace JsonApiDotNetCoreExampleTests.Acceptance
17+
{
18+
[Collection("WebHostCollection")]
19+
public class QueryFiltersTests
20+
{
21+
private TestFixture<TestStartup> _fixture;
22+
private AppDbContext _context;
23+
private Faker<User> _userFaker;
24+
25+
public QueryFiltersTests(TestFixture<TestStartup> fixture)
26+
{
27+
_fixture = fixture;
28+
_context = fixture.GetService<AppDbContext>();
29+
_userFaker = new Faker<User>()
30+
.RuleFor(u => u.Username, f => f.Internet.UserName())
31+
.RuleFor(u => u.Password, f => f.Internet.Password());
32+
}
33+
34+
[Fact]
35+
public async Task FiltersWithCustomQueryFiltersEquals()
36+
{
37+
// Arrange
38+
var user = _userFaker.Generate();
39+
var firstUsernameCharacter = user.Username[0];
40+
_context.Users.Add(user);
41+
_context.SaveChanges();
42+
43+
var httpMethod = new HttpMethod("GET");
44+
var route = $"/api/v1/users?filter[first-character]=eq:{firstUsernameCharacter}";
45+
var request = new HttpRequestMessage(httpMethod, route);
46+
47+
// Act
48+
var response = await _fixture.Client.SendAsync(request);
49+
50+
// Assert
51+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
52+
var body = await response.Content.ReadAsStringAsync();
53+
var deserializedBody = _fixture.GetService<IJsonApiDeSerializer>().DeserializeList<User>(body);
54+
var usersWithFirstCharacter = _context.Users.Where(u => u.Username[0] == firstUsernameCharacter);
55+
Assert.True(deserializedBody.All(u => u.Username[0] == firstUsernameCharacter));
56+
}
57+
58+
[Fact]
59+
public async Task FiltersWithCustomQueryFiltersLessThan()
60+
{
61+
// Arrange
62+
var aUser = _userFaker.Generate();
63+
aUser.Username = "alfred";
64+
var zUser = _userFaker.Generate();
65+
zUser.Username = "zac";
66+
_context.Users.AddRange(aUser, zUser);
67+
_context.SaveChanges();
68+
69+
var median = 'h';
70+
71+
var httpMethod = new HttpMethod("GET");
72+
var route = $"/api/v1/users?filter[first-character]=lt:{median}";
73+
var request = new HttpRequestMessage(httpMethod, route);
74+
75+
// Act
76+
var response = await _fixture.Client.SendAsync(request);
77+
78+
// Assert
79+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
80+
var body = await response.Content.ReadAsStringAsync();
81+
var deserializedBody = _fixture.GetService<IJsonApiDeSerializer>().DeserializeList<User>(body);
82+
var usersBeforeMedian = _context.Users.Where(u => u.Username[0] < median);
83+
Assert.True(deserializedBody.All(u => u.Username[0] < median));
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)