3
3
import uuid
4
4
5
5
from graphene .types .json import JSONString
6
+ from graphene .utils .str_converters import to_snake_case
6
7
from mongoengine .base import get_document
7
-
8
8
from . import advanced_types
9
- from .utils import import_single_dispatch , get_field_description
9
+ from .utils import import_single_dispatch , get_field_description , get_query_fields
10
+ from concurrent .futures import ThreadPoolExecutor , as_completed
10
11
11
12
singledispatch = import_single_dispatch ()
12
13
@@ -104,6 +105,49 @@ def convert_file_to_field(field, registry=None):
104
105
def convert_field_to_list (field , registry = None ):
105
106
base_type = convert_mongoengine_field (field .field , registry = registry )
106
107
if isinstance (base_type , graphene .Field ):
108
+ if isinstance (field .field , mongoengine .GenericReferenceField ):
109
+ def get_reference_objects (* args , ** kwargs ):
110
+ if args [0 ][1 ]:
111
+ document = get_document (args [0 ][0 ])
112
+ document_field = mongoengine .ReferenceField (document )
113
+ document_field = convert_mongoengine_field (document_field , registry )
114
+ document_field_type = document_field .get_type ().type ._meta .name
115
+ only_fields = [to_snake_case (i ) for i in
116
+ get_query_fields (args [0 ][3 ][0 ])[document_field_type ].keys ()]
117
+ return document .objects ().no_dereference ().only (* only_fields ).filter (pk__in = args [0 ][1 ])
118
+ else :
119
+ return []
120
+
121
+ def reference_resolver (root , * args , ** kwargs ):
122
+ choice_to_resolve = dict ()
123
+ to_resolve = getattr (root , field .name or field .db_name )
124
+ if to_resolve :
125
+ for each in to_resolve :
126
+ if each ['_cls' ] not in choice_to_resolve :
127
+ choice_to_resolve [each ['_cls' ]] = list ()
128
+ choice_to_resolve [each ['_cls' ]].append (each ["_ref" ].id )
129
+
130
+ pool = ThreadPoolExecutor (5 )
131
+ futures = list ()
132
+ for model , object_id_list in choice_to_resolve .items ():
133
+ futures .append (pool .submit (get_reference_objects , (model , object_id_list , registry , args )))
134
+ result = list ()
135
+ for x in as_completed (futures ):
136
+ result += x .result ()
137
+ to_resolve_object_ids = [each ["_ref" ].id for each in to_resolve ]
138
+ result_to_resolve_object_ids = [each .id for each in result ]
139
+ ordered_result = list ()
140
+ for each in to_resolve_object_ids :
141
+ ordered_result .append (result [result_to_resolve_object_ids .index (each )])
142
+ return ordered_result
143
+ return []
144
+
145
+ return graphene .List (
146
+ base_type ._type ,
147
+ description = get_field_description (field , registry ),
148
+ required = field .required ,
149
+ resolver = reference_resolver
150
+ )
107
151
return graphene .List (
108
152
base_type ._type ,
109
153
description = get_field_description (field , registry ),
@@ -121,7 +165,7 @@ def convert_field_to_list(field, registry=None):
121
165
# Non-relationship field
122
166
relations = (mongoengine .ReferenceField , mongoengine .EmbeddedDocumentField )
123
167
if not isinstance (base_type , (graphene .List , graphene .NonNull )) and not isinstance (
124
- field .field , relations
168
+ field .field , relations
125
169
):
126
170
base_type = type (base_type )
127
171
@@ -135,7 +179,6 @@ def convert_field_to_list(field, registry=None):
135
179
@convert_mongoengine_field .register (mongoengine .GenericEmbeddedDocumentField )
136
180
@convert_mongoengine_field .register (mongoengine .GenericReferenceField )
137
181
def convert_field_to_union (field , registry = None ):
138
-
139
182
_types = []
140
183
for choice in field .choices :
141
184
if isinstance (field , mongoengine .GenericReferenceField ):
@@ -162,6 +205,25 @@ def convert_field_to_union(field, registry=None):
162
205
)
163
206
Meta = type ("Meta" , (object ,), {"types" : tuple (_types )})
164
207
_union = type (name , (graphene .Union ,), {"Meta" : Meta })
208
+
209
+ def reference_resolver (root , * args , ** kwargs ):
210
+ dereferenced = getattr (root , field .name or field .db_name )
211
+ if dereferenced :
212
+ document = get_document (dereferenced ["_cls" ])
213
+ document_field = mongoengine .ReferenceField (document )
214
+ document_field = convert_mongoengine_field (document_field , registry )
215
+ _type = document_field .get_type ().type
216
+ only_fields = _type ._meta .only_fields .split ("," ) if isinstance (_type ._meta .only_fields ,
217
+ str ) else list ()
218
+ return document .objects ().no_dereference ().only (* list (
219
+ set (only_fields + [to_snake_case (i ) for i in get_query_fields (args [0 ])[_type ._meta .name ].keys ()]))).get (
220
+ pk = dereferenced ["_ref" ].id )
221
+ return None
222
+
223
+ if isinstance (field , mongoengine .GenericReferenceField ):
224
+ return graphene .Field (_union , resolver = reference_resolver ,
225
+ description = get_field_description (field , registry ))
226
+
165
227
return graphene .Field (_union )
166
228
167
229
@@ -171,11 +233,40 @@ def convert_field_to_union(field, registry=None):
171
233
def convert_field_to_dynamic (field , registry = None ):
172
234
model = field .document_type
173
235
236
+ def reference_resolver (root , * args , ** kwargs ):
237
+ document = getattr (root , field .name or field .db_name )
238
+ if document :
239
+ _type = registry .get_type_for_model (field .document_type )
240
+ only_fields = _type ._meta .only_fields .split ("," ) if isinstance (_type ._meta .only_fields ,
241
+ str ) else list ()
242
+ return field .document_type .objects ().no_dereference ().only (
243
+ * ((list (set (only_fields + [to_snake_case (i ) for i in get_query_fields (args [0 ]).keys ()]))))).get (
244
+ pk = document .id )
245
+ return None
246
+
247
+ def cached_reference_resolver (root , * args , ** kwargs ):
248
+ if field :
249
+ _type = registry .get_type_for_model (field .document_type )
250
+ only_fields = _type ._meta .only_fields .split ("," ) if isinstance (_type ._meta .only_fields ,
251
+ str ) else list ()
252
+ return field .document_type .objects ().no_dereference ().only (
253
+ * (list (set (only_fields + [to_snake_case (i ) for i in get_query_fields (args [0 ]).keys ()]))
254
+ )).get (
255
+ pk = getattr (root , field .name or field .db_name ))
256
+ return None
257
+
174
258
def dynamic_type ():
175
259
_type = registry .get_type_for_model (model )
176
260
if not _type :
177
261
return None
178
- return graphene .Field (_type , description = get_field_description (field , registry ))
262
+ elif isinstance (field , mongoengine .ReferenceField ):
263
+ return graphene .Field (_type , resolver = reference_resolver ,
264
+ description = get_field_description (field , registry ))
265
+ elif isinstance (field , mongoengine .CachedReferenceField ):
266
+ return graphene .Field (_type , resolver = cached_reference_resolver ,
267
+ description = get_field_description (field , registry ))
268
+ return graphene .Field (_type ,
269
+ description = get_field_description (field , registry ))
179
270
180
271
return graphene .Dynamic (dynamic_type )
181
272
@@ -185,11 +276,19 @@ def convert_lazy_field_to_dynamic(field, registry=None):
185
276
model = field .document_type
186
277
187
278
def lazy_resolver (root , * args , ** kwargs ):
188
- if getattr (root , field .name or field .db_name ):
189
- return getattr (root , field .name or field .db_name ).fetch ()
279
+ document = getattr (root , field .name or field .db_name )
280
+ if document :
281
+ _type = registry .get_type_for_model (document .document_type )
282
+ only_fields = _type ._meta .only_fields .split ("," ) if isinstance (_type ._meta .only_fields ,
283
+ str ) else list ()
284
+ return document .document_type .objects ().no_dereference ().only (
285
+ * (list (set ((only_fields + [to_snake_case (i ) for i in get_query_fields (args [0 ]).keys ()]))))).get (
286
+ pk = document .pk )
287
+ return None
190
288
191
289
def dynamic_type ():
192
290
_type = registry .get_type_for_model (model )
291
+
193
292
if not _type :
194
293
return None
195
294
return graphene .Field (
0 commit comments