@@ -86,36 +86,7 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
8686                // {1} 
8787                var  right  =  Expression . Constant ( convertedValue ,  property . PropertyType ) ; 
8888
89-                 Expression  body ; 
90-                 switch  ( filterQuery . FilterOperation ) 
91-                 { 
92-                     case  FilterOperations . eq : 
93-                         // {model.Id == 1} 
94-                         body  =  Expression . Equal ( left ,  right ) ; 
95-                         break ; 
96-                     case  FilterOperations . lt : 
97-                         // {model.Id < 1} 
98-                         body  =  Expression . LessThan ( left ,  right ) ; 
99-                         break ; 
100-                     case  FilterOperations . gt : 
101-                         // {model.Id > 1} 
102-                         body  =  Expression . GreaterThan ( left ,  right ) ; 
103-                         break ; 
104-                     case  FilterOperations . le : 
105-                         // {model.Id <= 1} 
106-                         body  =  Expression . LessThanOrEqual ( left ,  right ) ; 
107-                         break ; 
108-                     case  FilterOperations . ge : 
109-                         // {model.Id <= 1} 
110-                         body  =  Expression . GreaterThanOrEqual ( left ,  right ) ; 
111-                         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 } ") ; 
118-                 } 
89+                 var  body  =  GetFilterExpressionLambda ( left ,  right ,  filterQuery . FilterOperation ) ; 
11990
12091                var  lambda  =  Expression . Lambda < Func < TSource ,  bool > > ( body ,  parameter ) ; 
12192
@@ -126,27 +97,109 @@ public static IQueryable<TSource> Filter<TSource>(this IQueryable<TSource> sourc
12697                throw  new  JsonApiException ( "400" ,  $ "Could not cast { filterQuery . PropertyValue }  to { property . PropertyType . Name } ") ; 
12798            } 
12899        } 
100+ 
101+         public  static IQueryable < TSource >  Filter < TSource > ( this  IQueryable < TSource >  source ,  RelatedAttrFilterQuery  filterQuery ) 
102+         { 
103+             if  ( filterQuery  ==  null ) 
104+                 return  source ; 
105+ 
106+             var  concreteType  =  typeof ( TSource ) ; 
107+             var  relation  =  concreteType . GetProperty ( filterQuery . FilteredRelationship . InternalRelationshipName ) ; 
108+             if  ( relation  ==  null ) 
109+                 throw  new  ArgumentException ( $ "'{ filterQuery . FilteredRelationship . InternalRelationshipName } ' is not a valid relationship of '{ concreteType } '") ; 
110+ 
111+             var  relatedType  =  filterQuery . FilteredRelationship . Type ; 
112+             var  relatedAttr  =  relatedType . GetProperty ( filterQuery . FilteredAttribute . InternalAttributeName ) ; 
113+             if  ( relatedAttr  ==  null ) 
114+                 throw  new  ArgumentException ( $ "'{ filterQuery . FilteredAttribute . InternalAttributeName } ' is not a valid attribute of '{ filterQuery . FilteredRelationship . InternalRelationshipName } '") ; 
115+ 
116+             try 
117+             { 
118+                 // convert the incoming value to the target value type 
119+                 // "1" -> 1 
120+                 var  convertedValue  =  TypeHelper . ConvertType ( filterQuery . PropertyValue ,  relatedAttr . PropertyType ) ; 
121+                 // {model} 
122+                 var  parameter  =  Expression . Parameter ( concreteType ,  "model" ) ; 
123+ 
124+                 // {model.Relationship} 
125+                 var  leftRelationship  =  Expression . PropertyOrField ( parameter ,  relation . Name ) ; 
126+ 
127+                 // {model.Relationship.Attr} 
128+                 var  left  =  Expression . PropertyOrField ( leftRelationship ,  relatedAttr . Name ) ; 
129+ 
130+                 // {1} 
131+                 var  right  =  Expression . Constant ( convertedValue ,  relatedAttr . PropertyType ) ; 
132+ 
133+                 var  body  =  GetFilterExpressionLambda ( left ,  right ,  filterQuery . FilterOperation ) ; 
134+ 
135+                 var  lambda  =  Expression . Lambda < Func < TSource ,  bool > > ( body ,  parameter ) ; 
136+ 
137+                 return  source . Where ( lambda ) ; 
138+             } 
139+             catch  ( FormatException ) 
140+             { 
141+                 throw  new  JsonApiException ( "400" ,  $ "Could not cast { filterQuery . PropertyValue }  to { relatedAttr . PropertyType . Name } ") ; 
142+             } 
143+         } 
144+ 
145+         private  static Expression  GetFilterExpressionLambda ( Expression  left ,  Expression  right ,  FilterOperations  operation ) 
146+         { 
147+             Expression  body ; 
148+             switch  ( operation ) 
149+             { 
150+                 case  FilterOperations . eq : 
151+                     // {model.Id == 1} 
152+                     body  =  Expression . Equal ( left ,  right ) ; 
153+                     break ; 
154+                 case  FilterOperations . lt : 
155+                     // {model.Id < 1} 
156+                     body  =  Expression . LessThan ( left ,  right ) ; 
157+                     break ; 
158+                 case  FilterOperations . gt : 
159+                     // {model.Id > 1} 
160+                     body  =  Expression . GreaterThan ( left ,  right ) ; 
161+                     break ; 
162+                 case  FilterOperations . le : 
163+                     // {model.Id <= 1} 
164+                     body  =  Expression . LessThanOrEqual ( left ,  right ) ; 
165+                     break ; 
166+                 case  FilterOperations . ge : 
167+                     // {model.Id <= 1} 
168+                     body  =  Expression . GreaterThanOrEqual ( left ,  right ) ; 
169+                     break ; 
170+                 case  FilterOperations . like : 
171+                     // {model.Id <= 1} 
172+                     body  =  Expression . Call ( left ,  "Contains" ,  null ,  right ) ; 
173+                     break ; 
174+                 default : 
175+                     throw  new  JsonApiException ( "500" ,  $ "Unknown filter operation { operation } ") ; 
176+             } 
177+ 
178+             return  body ; 
179+         } 
180+ 
181+ 
129182        public  static IQueryable < TSource >  Select < TSource > ( this  IQueryable < TSource >  source ,  IEnumerable < string >  columns ) 
130183        { 
131-             if ( columns  ==  null  ||  columns . Count ( )  ==  0 ) 
184+             if   ( columns  ==  null  ||  columns . Count ( )  ==  0 ) 
132185                return  source ; 
133186
134187            var  sourceType  =  source . ElementType ; 
135-              
188+ 
136189            var  resultType  =  typeof ( TSource ) ; 
137190
138191            // {model} 
139192            var  parameter  =  Expression . Parameter ( sourceType ,  "model" ) ; 
140-              
193+ 
141194            var  bindings  =  columns . Select ( column =>  Expression . Bind ( 
142195                resultType . GetProperty ( column ) ,  Expression . PropertyOrField ( parameter ,  column ) ) ) ; 
143-              
196+ 
144197            // { new Model () { Property = model.Property } } 
145198            var  body  =  Expression . MemberInit ( Expression . New ( resultType ) ,  bindings ) ; 
146-              
199+ 
147200            // { model => new TodoItem() { Property = model.Property } } 
148201            var  selector  =  Expression . Lambda ( body ,  parameter ) ; 
149-              
202+ 
150203            return  source . Provider . CreateQuery < TSource > ( 
151204                Expression . Call ( typeof ( Queryable ) ,  "Select" ,  new  Type [ ]  {  sourceType ,  resultType  } , 
152205                source . Expression ,  Expression . Quote ( selector ) ) ) ; 
0 commit comments