Skip to content

Commit 0be3300

Browse files
committed
Revert filter back
1 parent 04172a4 commit 0be3300

File tree

8 files changed

+56
-121
lines changed

8 files changed

+56
-121
lines changed

src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Reflection;
66
using JsonApiDotNetCore.Internal;
77
using JsonApiDotNetCore.Internal.Query;
8-
using JsonApiDotNetCore.Models;
98
using JsonApiDotNetCore.Services;
109

1110
namespace JsonApiDotNetCore.Extensions
@@ -122,7 +121,7 @@ public static IOrderedQueryable<TSource> Sort<TSource>(this IOrderedQueryable<TS
122121
return sortQuery.Direction == SortDirection.Descending
123122
? source.ThenByDescending(attr.GetPropertyPath())
124123
: source.ThenBy(attr.GetPropertyPath());
125-
}
124+
}
126125

127126
public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
128127
=> CallGenericOrderMethod(source, propertyName, "OrderBy");
@@ -183,7 +182,7 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
183182
return source;
184183

185184
if (filterQuery.FilterOperation == FilterOperations.@in || filterQuery.FilterOperation == FilterOperations.nin)
186-
return CallGenericWhereContainsMethod(source,filterQuery);
185+
return CallGenericWhereContainsMethod(source, filterQuery);
187186
else
188187
return CallGenericWhereMethod(source, filterQuery);
189188
}
@@ -216,7 +215,7 @@ private static Expression GetFilterExpressionLambda(Expression left, Expression
216215
case FilterOperations.like:
217216
body = Expression.Call(left, "Contains", null, right);
218217
break;
219-
// {model.Id != 1}
218+
// {model.Id != 1}
220219
case FilterOperations.ne:
221220
body = Expression.NotEqual(left, right);
222221
break;

src/JsonApiDotNetCore/Internal/Query/BaseFilterQuery.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ public BaseFilterQuery(
1111
: base(jsonApiContext, filterQuery)
1212
{
1313
PropertyValue = filterQuery.Value;
14-
FilterOperation = filterQuery.OperationType;
14+
FilterOperation = GetFilterOperation(filterQuery.Operation);
1515
}
1616

17-
[Obsolete("Use " + nameof(FilterQuery.OperationType) + " instead.")]
18-
protected FilterOperations GetFilterOperation(string prefix)
17+
public string PropertyValue { get; }
18+
public FilterOperations FilterOperation { get; }
19+
20+
private FilterOperations GetFilterOperation(string prefix)
1921
{
2022
if (prefix.Length == 0) return FilterOperations.eq;
2123

@@ -25,7 +27,5 @@ protected FilterOperations GetFilterOperation(string prefix)
2527
return opertion;
2628
}
2729

28-
public string PropertyValue { get; }
29-
public FilterOperations FilterOperation { get; }
3030
}
3131
}

src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs

+1-18
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,18 @@ namespace JsonApiDotNetCore.Internal.Query
66
{
77
public class FilterQuery : BaseQuery
88
{
9-
[Obsolete("Use constructor with FilterOperations operationType paremeter. Filter operation should be provided " +
10-
"as enum type, not by string.")]
119
public FilterQuery(string attribute, string value, string operation)
12-
:base(attribute)
13-
{
14-
Key = attribute.ToProperCase();
15-
Value = value;
16-
Operation = operation;
17-
18-
Enum.TryParse(operation, out FilterOperations opertion);
19-
OperationType = opertion;
20-
}
21-
22-
public FilterQuery(string attribute, string value, FilterOperations operationType)
2310
: base(attribute)
2411
{
2512
Key = attribute.ToProperCase();
2613
Value = value;
27-
Operation = operationType.ToString();
28-
OperationType = operationType;
14+
Operation = operation;
2915
}
3016

3117
[Obsolete("Key has been replaced by '" + nameof(Attribute) + "'. Members should be located by their public name, not by coercing the provided value to the internal name.")]
3218
public string Key { get; set; }
3319
public string Value { get; set; }
34-
[Obsolete("Use '" + nameof(OperationType) + "' instead.")]
3520
public string Operation { get; set; }
3621

37-
public FilterOperations OperationType { get; set; }
38-
3922
}
4023
}

src/JsonApiDotNetCore/Services/QueryComposer.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ public string Compose(IJsonApiContext jsonApiContext)
3030
private string ComposeSingleFilter(FilterQuery query)
3131
{
3232
var result = "&filter";
33-
result += QueryConstants.OPEN_BRACKET + query.Attribute + QueryConstants.CLOSE_BRACKET + "=" + query.OperationType + QueryConstants.COLON + query.Value;
33+
var operation = string.IsNullOrWhiteSpace(query.Operation) ? query.Operation : query.Operation + ":";
34+
result += QueryConstants.OPEN_BRACKET + query.Attribute + QueryConstants.CLOSE_BRACKET + "=" + operation + query.Value;
3435
return result;
3536
}
3637
}

src/JsonApiDotNetCore/Services/QueryParser.cs

+32-81
Original file line numberDiff line numberDiff line change
@@ -85,29 +85,32 @@ protected virtual List<FilterQuery> ParseFilterQuery(string key, string value)
8585
var propertyName = key.Split(QueryConstants.OPEN_BRACKET, QueryConstants.CLOSE_BRACKET)[1];
8686

8787
// InArray case
88-
var arrOpVal = ParseFilterOperationAndValue(value);
89-
if (arrOpVal.operation == FilterOperations.@in || arrOpVal.operation == FilterOperations.nin)
90-
queries.Add(new FilterQuery(propertyName, arrOpVal.value, arrOpVal.operation));
88+
string op = GetFilterOperation(value);
89+
if (string.Equals(op, FilterOperations.@in.ToString(), StringComparison.OrdinalIgnoreCase)
90+
|| string.Equals(op, FilterOperations.nin.ToString(), StringComparison.OrdinalIgnoreCase))
91+
{
92+
(var operation, var filterValue) = ParseFilterOperation(value);
93+
queries.Add(new FilterQuery(propertyName, filterValue, op));
94+
}
9195
else
9296
{
9397
var values = value.Split(QueryConstants.COMMA);
9498
foreach (var val in values)
9599
{
96-
var opVal = ParseFilterOperationAndValue(val);
97-
queries.Add(new FilterQuery(propertyName, opVal.value, opVal.operation));
100+
(var operation, var filterValue) = ParseFilterOperation(val);
101+
queries.Add(new FilterQuery(propertyName, filterValue, operation));
98102
}
99103
}
100104

101105
return queries;
102106
}
103107

104-
[Obsolete("Use " + nameof(ParseFilterOperationAndValue) + " method instead.")]
105108
protected virtual (string operation, string value) ParseFilterOperation(string value)
106109
{
107110
if (value.Length < 3)
108111
return (string.Empty, value);
109112

110-
var operation = GetFilterOperationOld(value);
113+
var operation = GetFilterOperation(value);
111114
var values = value.Split(QueryConstants.COLON);
112115

113116
if (string.IsNullOrEmpty(operation))
@@ -118,63 +121,6 @@ protected virtual (string operation, string value) ParseFilterOperation(string v
118121
return (operation, value);
119122
}
120123

121-
/// <summary>
122-
/// Parse filter operation enum and value by string value.
123-
/// Input string can contain:
124-
/// a) property value only, then FilterOperations.eq and value is returned
125-
/// b) filter prefix and value e.g. "prefix:value", then FilterOperations.prefix and value is returned
126-
/// In case of prefix is provided and is not in FilterOperations enum,
127-
/// invalid filter prefix exception is thrown.
128-
/// </summary>
129-
/// <param name="input"></param>
130-
/// <returns></returns>
131-
protected virtual (FilterOperations operation, string value) ParseFilterOperationAndValue(string input)
132-
{
133-
// value is empty
134-
if (input.Length == 0)
135-
return (FilterOperations.eq, input);
136-
137-
// split value
138-
var values = input.Split(QueryConstants.COLON);
139-
// value only
140-
if (values.Length == 1)
141-
return (FilterOperations.eq, input);
142-
// prefix:value
143-
else if (values.Length == 2)
144-
{
145-
var (operation, succeeded) = GetFilterOperation(values[0]);
146-
if (succeeded == false)
147-
throw new JsonApiException(400, $"Invalid filter prefix '{values[0]}'");
148-
149-
return (operation, values[1]);
150-
}
151-
// some:colon:value OR prefix:some:colon:value (datetime)
152-
else
153-
{
154-
// succeeded = false means no prefix found => some value with colons(datetime)
155-
// succeeded = true means prefix provide + some value with colons(datetime)
156-
var (operation, succeeded) = GetFilterOperation(values[0]);
157-
var value = "";
158-
// datetime
159-
if (succeeded == false)
160-
value = string.Join(QueryConstants.COLON_STR, values);
161-
else
162-
value = string.Join(QueryConstants.COLON_STR, values.Skip(1));
163-
return (operation, value);
164-
}
165-
}
166-
167-
/// <summary>
168-
/// Returns typed operation result and info about parsing success
169-
/// </summary>
170-
/// <param name="operation">String represented operation</param>
171-
/// <returns></returns>
172-
private static (FilterOperations operation, bool succeeded) GetFilterOperation(string operation)
173-
{
174-
var success = Enum.TryParse(operation, out FilterOperations opertion);
175-
return (opertion, success);
176-
}
177-
178124
protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, string value)
179125
{
180126
// expected input = page[size]=10
@@ -247,15 +193,35 @@ protected virtual List<string> ParseFieldsQuery(string key, string value)
247193
var fields = value.Split(QueryConstants.COMMA);
248194
foreach (var field in fields)
249195
{
250-
var attr = GetAttribute(field);
196+
var attr = _controllerContext.RequestEntity
197+
.Attributes
198+
.SingleOrDefault(a => a.Is(field));
199+
200+
if (attr == null) throw new JsonApiException(400, $"'{_controllerContext.RequestEntity.EntityName}' does not contain '{field}'.");
201+
251202
var internalAttrName = attr.InternalAttributeName;
252203
includedFields.Add(internalAttrName);
253204
}
254205

255206
return includedFields;
256207
}
257208

258-
private string GetFilterOperationOld(string value)
209+
protected virtual AttrAttribute GetAttribute(string propertyName)
210+
{
211+
try
212+
{
213+
return _controllerContext
214+
.RequestEntity
215+
.Attributes
216+
.Single(attr => attr.Is(propertyName));
217+
}
218+
catch (InvalidOperationException e)
219+
{
220+
throw new JsonApiException(400, $"Attribute '{propertyName}' does not exist on resource '{_controllerContext.RequestEntity.EntityName}'", e);
221+
}
222+
}
223+
224+
private string GetFilterOperation(string value)
259225
{
260226
var values = value.Split(QueryConstants.COLON);
261227

@@ -269,20 +235,5 @@ private string GetFilterOperationOld(string value)
269235

270236
return operation;
271237
}
272-
273-
protected virtual AttrAttribute GetAttribute(string attribute)
274-
{
275-
try
276-
{
277-
return _controllerContext
278-
.RequestEntity
279-
.Attributes
280-
.Single(attr => attr.Is(attribute));
281-
}
282-
catch (InvalidOperationException e)
283-
{
284-
throw new JsonApiException(400, $"Attribute '{attribute}' does not exist on resource '{_controllerContext.RequestEntity.EntityName}'", e);
285-
}
286-
}
287238
}
288239
}

test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs

+7-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ public async Task Can_Select_Sparse_Fieldsets()
3535
{
3636
// arrange
3737
var fields = new List<string> { "Id", "Description", "CreatedDate", "AchievedDate" };
38-
var todoItem = new TodoItem {
38+
var todoItem = new TodoItem
39+
{
3940
Description = "description",
4041
Ordinal = 1,
4142
CreatedDate = DateTime.Now,
@@ -50,7 +51,7 @@ public async Task Can_Select_Sparse_Fieldsets()
5051
// act
5152
var query = _dbContext
5253
.TodoItems
53-
.Where(t=>t.Id == todoItem.Id)
54+
.Where(t => t.Id == todoItem.Id)
5455
.Select(fields);
5556

5657
var resultSql = StringExtensions.Normalize(query.ToSql());
@@ -68,14 +69,15 @@ public async Task Can_Select_Sparse_Fieldsets()
6869
public async Task Fields_Query_Selects_Sparse_Field_Sets()
6970
{
7071
// arrange
71-
var todoItem = new TodoItem {
72+
var todoItem = new TodoItem
73+
{
7274
Description = "description",
73-
Ordinal = 1,
75+
Ordinal = 1,
7476
CreatedDate = DateTime.Now
7577
};
7678
_dbContext.TodoItems.Add(todoItem);
7779
await _dbContext.SaveChangesAsync();
78-
80+
7981
var builder = new WebHostBuilder()
8082
.UseStartup<Startup>();
8183
var httpMethod = new HttpMethod("GET");

test/UnitTests/Services/QueryComposerTests.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void Can_ComposeEqual_FilterStringForUrl()
2323
var querySet = new QuerySet();
2424
List<FilterQuery> filters = new List<FilterQuery>();
2525
filters.Add(filter);
26-
querySet.Filters=filters;
26+
querySet.Filters = filters;
2727

2828
_jsonApiContext
2929
.Setup(m => m.QuerySet)
@@ -56,7 +56,7 @@ public void Can_ComposeLessThan_FilterStringForUrl()
5656
// act
5757
var filterString = queryComposer.Compose(_jsonApiContext.Object);
5858
// assert
59-
Assert.Equal("&filter[attribute]=le:value&filter[attribute2]=eq:value2", filterString);
59+
Assert.Equal("&filter[attribute]=le:value&filter[attribute2]=value2", filterString);
6060
}
6161

6262
[Fact]
@@ -73,7 +73,7 @@ public void NoFilter_Compose_EmptyStringReturned()
7373
// act
7474
var filterString = queryComposer.Compose(_jsonApiContext.Object);
7575
// assert
76-
Assert.Equal("", filterString);
76+
Assert.Equal("", filterString);
7777
}
7878
}
7979
}

test/UnitTests/Services/QueryParser_Tests.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using JsonApiDotNetCore.Configuration;
44
using JsonApiDotNetCore.Controllers;
55
using JsonApiDotNetCore.Internal;
6-
using JsonApiDotNetCore.Internal.Query;
76
using JsonApiDotNetCore.Models;
87
using JsonApiDotNetCore.Services;
98
using Microsoft.AspNetCore.Http;
@@ -100,7 +99,7 @@ public void Filters_Properly_Parses_DateTime_Without_Operation()
10099

101100
// assert
102101
Assert.Equal(dt, querySet.Filters.Single(f => f.Attribute == "key").Value);
103-
Assert.Equal(FilterOperations.eq, querySet.Filters.Single(f => f.Attribute == "key").OperationType);
102+
Assert.Equal(string.Empty, querySet.Filters.Single(f => f.Attribute == "key").Operation);
104103
}
105104

106105
[Fact]
@@ -247,7 +246,7 @@ public void Can_Parse_Fields_Query()
247246
.Returns(new ContextEntity
248247
{
249248
EntityName = type,
250-
Attributes = new List<AttrAttribute>
249+
Attributes = new List<AttrAttribute>
251250
{
252251
new AttrAttribute(attrName)
253252
{
@@ -286,7 +285,7 @@ public void Throws_JsonApiException_If_Field_DoesNotExist()
286285
.Returns(new ContextEntity
287286
{
288287
EntityName = type,
289-
Attributes = new List<AttrAttribute>()
288+
Attributes = new List<AttrAttribute>()
290289
});
291290

292291
var queryParser = new QueryParser(_controllerContextMock.Object, new JsonApiOptions());

0 commit comments

Comments
 (0)