33using System . Linq ;
44using JsonApiDotNetCore . Configuration ;
55using JsonApiDotNetCore . Controllers ;
6- using JsonApiDotNetCore . Extensions ;
76using JsonApiDotNetCore . Internal ;
87using JsonApiDotNetCore . Internal . Query ;
98using JsonApiDotNetCore . Models ;
@@ -18,8 +17,17 @@ public class QueryParser : IQueryParser {
1817 private readonly IControllerContext _controllerContext ;
1918 private readonly JsonApiOptions _options ;
2019
20+ private const string FILTER = "filter" ;
21+ private const string SORT = "sort" ;
22+ private const string INCLUDE = "include" ;
23+ private const string PAGE = "page" ;
24+ private const string FIELDS = "fields" ;
2125 private const char OPEN_BRACKET = '[' ;
2226 private const char CLOSE_BRACKET = ']' ;
27+ private const char COMMA = ',' ;
28+ private const char COLON = ':' ;
29+ private const string COLON_STR = ":" ;
30+
2331 public QueryParser (
2432 IControllerContext controllerContext ,
2533 JsonApiOptions options ) {
@@ -32,31 +40,31 @@ public virtual QuerySet Parse(IQueryCollection query) {
3240 var disabledQueries = _controllerContext . GetControllerAttribute < DisableQueryAttribute > ( ) ? . QueryParams ?? QueryParams . None ;
3341
3442 foreach ( var pair in query ) {
35- if ( pair . Key . StartsWith ( "filter" ) ) {
43+ if ( pair . Key . StartsWith ( FILTER ) ) {
3644 if ( disabledQueries . HasFlag ( QueryParams . Filter ) == false )
3745 querySet . Filters . AddRange ( ParseFilterQuery ( pair . Key , pair . Value ) ) ;
3846 continue ;
3947 }
4048
41- if ( pair . Key . StartsWith ( "sort" ) ) {
49+ if ( pair . Key . StartsWith ( SORT ) ) {
4250 if ( disabledQueries . HasFlag ( QueryParams . Sort ) == false )
4351 querySet . SortParameters = ParseSortParameters ( pair . Value ) ;
4452 continue ;
4553 }
4654
47- if ( pair . Key . StartsWith ( "include" ) ) {
55+ if ( pair . Key . StartsWith ( INCLUDE ) ) {
4856 if ( disabledQueries . HasFlag ( QueryParams . Include ) == false )
4957 querySet . IncludedRelationships = ParseIncludedRelationships ( pair . Value ) ;
5058 continue ;
5159 }
5260
53- if ( pair . Key . StartsWith ( "page" ) ) {
61+ if ( pair . Key . StartsWith ( PAGE ) ) {
5462 if ( disabledQueries . HasFlag ( QueryParams . Page ) == false )
5563 querySet . PageQuery = ParsePageQuery ( querySet . PageQuery , pair . Key , pair . Value ) ;
5664 continue ;
5765 }
5866
59- if ( pair . Key . StartsWith ( "fields" ) ) {
67+ if ( pair . Key . StartsWith ( FIELDS ) ) {
6068 if ( disabledQueries . HasFlag ( QueryParams . Fields ) == false )
6169 querySet . Fields = ParseFieldsQuery ( pair . Key , pair . Value ) ;
6270 continue ;
@@ -76,10 +84,9 @@ protected virtual List<FilterQuery> ParseFilterQuery(string key, string value) {
7684
7785 var propertyName = key . Split ( OPEN_BRACKET , CLOSE_BRACKET ) [ 1 ] ;
7886
79- var values = value . Split ( ',' ) ;
87+ var values = value . Split ( COMMA ) ;
8088 foreach ( var val in values ) {
81- ( var operation ,
82- var filterValue ) = ParseFilterOperation ( val ) ;
89+ ( var operation , var filterValue ) = ParseFilterOperation ( val ) ;
8390 queries . Add ( new FilterQuery ( propertyName , filterValue , operation ) ) ;
8491 }
8592
@@ -90,7 +97,7 @@ protected virtual(string operation, string value) ParseFilterOperation(string va
9097 if ( value . Length < 3 )
9198 return ( string . Empty , value ) ;
9299
93- var operation = value . Split ( ':' ) ;
100+ var operation = value . Split ( COLON ) ;
94101
95102 if ( operation . Length == 1 )
96103 return ( string . Empty , value ) ;
@@ -100,7 +107,7 @@ protected virtual(string operation, string value) ParseFilterOperation(string va
100107 return ( string . Empty , value ) ;
101108
102109 var prefix = operation [ 0 ] ;
103- value = string . Join ( ":" , operation . Skip ( 1 ) ) ;
110+ value = string . Join ( COLON_STR , operation . Skip ( 1 ) ) ;
104111
105112 return ( prefix , value ) ;
106113 }
@@ -110,11 +117,14 @@ protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, stri
110117 // page[number]=1
111118 pageQuery = pageQuery ?? new PageQuery ( ) ;
112119
113- var propertyName = key . Split ( '[' , ']' ) [ 1 ] ;
120+ var propertyName = key . Split ( OPEN_BRACKET , CLOSE_BRACKET ) [ 1 ] ;
121+
122+ const string SIZE = "size" ;
123+ const string NUMBER = "number" ;
114124
115- if ( propertyName == "size" )
125+ if ( propertyName == SIZE )
116126 pageQuery . PageSize = Convert . ToInt32 ( value ) ;
117- else if ( propertyName == "number" )
127+ else if ( propertyName == NUMBER )
118128 pageQuery . PageOffset = Convert . ToInt32 ( value ) ;
119129
120130 return pageQuery ;
@@ -123,11 +133,11 @@ protected virtual PageQuery ParsePageQuery(PageQuery pageQuery, string key, stri
123133 // sort=id,name
124134 // sort=-id
125135 protected virtual List < SortQuery > ParseSortParameters ( string value ) {
126- const char SORT_DELIMITER = ',' ;
136+ var sortParameters = new List < SortQuery > ( ) ;
137+
127138 const char DESCENDING_SORT_OPERATOR = '-' ;
139+ var sortSegments = value . Split ( COMMA ) ;
128140
129- var sortParameters = new List < SortQuery > ( ) ;
130- var sortSegments = value . Split ( SORT_DELIMITER ) ;
131141 foreach ( var sortSegment in sortSegments ) {
132142
133143 var propertyName = sortSegment ;
@@ -147,24 +157,26 @@ protected virtual List<SortQuery> ParseSortParameters(string value) {
147157 }
148158
149159 protected virtual List < string > ParseIncludedRelationships ( string value ) {
150- if ( value . Contains ( "." ) )
160+ const string NESTED_DELIMITER = "." ;
161+ if ( value . Contains ( NESTED_DELIMITER ) )
151162 throw new JsonApiException ( 400 , "Deeply nested relationships are not supported" ) ;
152163
153164 return value
154- . Split ( ',' )
165+ . Split ( COMMA )
155166 . ToList ( ) ;
156167 }
157168
158169 protected virtual List < string > ParseFieldsQuery ( string key , string value ) {
159170 // expected: fields[TYPE]=prop1,prop2
160- var typeName = key . Split ( '[' , ']' ) [ 1 ] ;
171+ var typeName = key . Split ( OPEN_BRACKET , CLOSE_BRACKET ) [ 1 ] ;
161172
162- var includedFields = new List < string > { "Id" } ;
173+ const string ID = "Id" ;
174+ var includedFields = new List < string > { ID } ;
163175
164176 if ( typeName != _controllerContext . RequestEntity . EntityName )
165177 return includedFields ;
166178
167- var fields = value . Split ( ',' ) ;
179+ var fields = value . Split ( COMMA ) ;
168180 foreach ( var field in fields ) {
169181 var internalAttrName = _controllerContext . RequestEntity
170182 . Attributes
@@ -176,11 +188,17 @@ protected virtual List<string> ParseFieldsQuery(string key, string value) {
176188 return includedFields ;
177189 }
178190
179- protected virtual AttrAttribute GetAttribute ( string propertyName ) => _controllerContext
180- . RequestEntity
181- . Attributes
182- . FirstOrDefault ( attr =>
183- string . Equals ( attr . PublicAttributeName , propertyName , StringComparison . OrdinalIgnoreCase )
184- ) ;
191+ protected virtual AttrAttribute GetAttribute ( string propertyName ) {
192+ try {
193+ return _controllerContext
194+ . RequestEntity
195+ . Attributes
196+ . Single ( attr =>
197+ string . Equals ( attr . PublicAttributeName , propertyName , StringComparison . OrdinalIgnoreCase )
198+ ) ;
199+ } catch ( InvalidOperationException e ) {
200+ throw new JsonApiException ( 400 , $ "Attribute '{ propertyName } ' does not exist on resource '{ _controllerContext . RequestEntity . EntityName } '") ;
201+ }
202+ }
185203 }
186204}
0 commit comments