32
32
sort_argument_for_object_type ,
33
33
sort_enum_for_object_type ,
34
34
)
35
- from .filters import BaseTypeFilter , FieldFilter , RelationshipFilter
35
+ from .filters import BaseTypeFilter , FieldFilter , RelationshipFilter , SQLAlchemyFilterInputField
36
36
from .registry import Registry , get_global_registry
37
37
from .resolvers import get_attr_resolver , get_custom_resolver
38
38
from .utils import (
@@ -151,13 +151,13 @@ def filter_field_from_field(
151
151
type_ ,
152
152
registry : Registry ,
153
153
model_attr : Any ,
154
- ) -> Optional [Union [graphene .InputField , graphene .Dynamic ]]:
154
+ model_attr_name : str
155
+ ) -> Optional [graphene .InputField ]:
155
156
# Field might be a SQLAlchemyObjectType, due to hybrid properties
156
157
if issubclass (type_ , SQLAlchemyObjectType ):
157
158
filter_class = registry .get_filter_for_base_type (type_ )
158
- return graphene .InputField (filter_class )
159
159
# Enum Special Case
160
- if issubclass (type_ , graphene .Enum ) and isinstance (model_attr , ColumnProperty ):
160
+ elif issubclass (type_ , graphene .Enum ) and isinstance (model_attr , ColumnProperty ):
161
161
column = model_attr .columns [0 ]
162
162
model_enum_type : Optional [sqlalchemy .types .Enum ] = getattr (column , "type" , None )
163
163
if not getattr (model_enum_type , "enum_class" , None ):
@@ -168,16 +168,16 @@ def filter_field_from_field(
168
168
filter_class = registry .get_filter_for_scalar_type (type_ )
169
169
if not filter_class :
170
170
warnings .warn (
171
- f"No compatible filters found for { field .type } . Skipping field."
171
+ f"No compatible filters found for { field .type } with db name { model_attr_name } . Skipping field."
172
172
)
173
173
return None
174
- return graphene . InputField (filter_class )
174
+ return SQLAlchemyFilterInputField (filter_class , model_attr_name )
175
175
176
176
177
177
def resolve_dynamic_relationship_filter (
178
178
field : graphene .Dynamic ,
179
179
registry : Registry ,
180
- model_attr : Any ,
180
+ model_attr_name : str
181
181
) -> Optional [Union [graphene .InputField , graphene .Dynamic ]]:
182
182
# Resolve Dynamic Type
183
183
type_ = get_nullable_type (field .get_type ())
@@ -200,39 +200,44 @@ def resolve_dynamic_relationship_filter(
200
200
reg_res = None
201
201
202
202
if not reg_res :
203
+ warnings .warn (
204
+ f"No compatible filters found for { field } with db name { model_attr_name } . Skipping field."
205
+ )
203
206
return None
204
207
205
- return graphene . InputField (reg_res )
208
+ return SQLAlchemyFilterInputField (reg_res , model_attr_name )
206
209
207
210
208
211
def filter_field_from_type_field (
209
212
field : Union [graphene .Field , graphene .Dynamic , Type [UnmountedType ]],
210
213
registry : Registry ,
211
214
filter_type : Optional [Type ],
212
215
model_attr : Any ,
216
+ model_attr_name : str
213
217
) -> Optional [Union [graphene .InputField , graphene .Dynamic ]]:
214
218
# If a custom filter type was set for this field, use it here
215
219
if filter_type :
216
- return graphene . InputField (filter_type )
220
+ return SQLAlchemyFilterInputField (filter_type , model_attr_name )
217
221
elif issubclass (type (field ), graphene .Scalar ):
218
222
filter_class = registry .get_filter_for_scalar_type (type (field ))
219
- return graphene . InputField (filter_class )
223
+ return SQLAlchemyFilterInputField (filter_class , model_attr_name )
220
224
# If the generated field is Dynamic, it is always a relationship
221
225
# (due to graphene-sqlalchemy's conversion mechanism).
222
226
elif isinstance (field , graphene .Dynamic ):
223
- return Dynamic (partial (resolve_dynamic_relationship_filter , field , registry , model_attr ))
224
- elif isinstance (field , graphene .Field ):
225
- if inspect .isfunction (field ._type ) or isinstance (field ._type , partial ):
226
- return Dynamic (lambda : filter_field_from_field (field , get_nullable_type (field .type ), registry , model_attr ))
227
- else :
228
- return filter_field_from_field (field , get_nullable_type (field .type ), registry , model_attr )
227
+ return Dynamic (partial (resolve_dynamic_relationship_filter , field , registry , model_attr_name ))
229
228
# Unsupported but theoretically possible cases, please drop us an issue with reproduction if you need them
230
229
elif isinstance (field , graphene .List ) or isinstance (field ._type , graphene .List ):
231
230
# Pure lists are not yet supported
232
231
pass
233
232
elif isinstance (field ._type , graphene .Dynamic ):
234
233
# Fields with nested dynamic Dynamic are not yet supported
235
234
pass
235
+ # Order matters, this comes last as field._type == list also matches Field
236
+ elif isinstance (field , graphene .Field ):
237
+ if inspect .isfunction (field ._type ) or isinstance (field ._type , partial ):
238
+ return Dynamic (lambda : filter_field_from_field (field , get_nullable_type (field .type ), registry , model_attr , model_attr_name ))
239
+ else :
240
+ return filter_field_from_field (field , get_nullable_type (field .type ), registry , model_attr , model_attr_name )
236
241
237
242
238
243
def get_polymorphic_on (model ):
@@ -372,7 +377,7 @@ def construct_fields_and_filters(
372
377
fields [orm_field_name ] = field
373
378
if filtering_enabled_for_field :
374
379
filters [orm_field_name ] = filter_field_from_type_field (
375
- field , registry , filter_type , attr
380
+ field , registry , filter_type , attr , attr_name
376
381
)
377
382
378
383
return fields , filters
0 commit comments