Skip to content

Commit bf73e6f

Browse files
committed
Merge branch 'test-query'
2 parents 42abdf3 + 7ef6f65 commit bf73e6f

File tree

8 files changed

+243
-28
lines changed

8 files changed

+243
-28
lines changed

graphene_mongoengine/converter.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from graphene import (ID, Boolean, Dynamic, Enum, Field, Float, Int, List,
2-
NonNull, String, UUID)
2+
NonNull, String, UUID, is_node)
33
from graphene.types.datetime import DateTime, Time
44
from graphene.types.json import JSONString
55
from graphene.utils.str_converters import to_camel_case, to_const
@@ -65,7 +65,10 @@ def convert_postgres_array_to_list(field, registry=None):
6565
base_type = convert_mongoengine_field(field.field, registry=registry)
6666
if isinstance(base_type, (Dynamic)):
6767
base_type = base_type.get_type()._type
68-
if not isinstance(base_type, (List, NonNull)):
68+
if is_node(base_type):
69+
return MongoengineConnectionField(base_type)
70+
elif not isinstance(base_type, (List, NonNull)) \
71+
and not isinstance(field.field, mongoengine.ReferenceField):
6972
base_type = type(base_type)
7073
return List(base_type, description=field.db_field, required=not field.null)
7174

@@ -80,9 +83,6 @@ def dynamic_type():
8083
if not _type:
8184
return None
8285

83-
if isinstance(model, mongoengine.EmbeddedDocument):
84-
return MongoengineConnectionField(_type)
85-
8686
return Field(_type)
8787

8888
return Dynamic(dynamic_type)

graphene_mongoengine/fields.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ def get_resolver(self, parent_resolver):
2929

3030
class MongoengineConnectionField(ConnectionField):
3131

32-
def __init__(self, *args, **kwargs):
33-
super(MongoengineConnectionField, self).__init(
32+
def __init__(self, type, *args, **kwargs):
33+
super(MongoengineConnectionField, self).__init__(
34+
type,
3435
*args,
3536
**kwargs
3637
)
@@ -39,7 +40,7 @@ def __init__(self, *args, **kwargs):
3940
def type(self):
4041
from .types import MongoengineObjectType
4142
_type = super(ConnectionField, self).type
42-
assert issubclass(_type, MongoengineObjectType), "MongoengineConnectionField only accepts DjangoObjectType types"
43+
assert issubclass(_type, MongoengineObjectType), "MongoengineConnectionField only accepts MongoengineObjectType types"
4344
assert _type._meta.connection, "The type {} doesn't have a connection".format(_type.__name__)
4445
return _type._meta.connection
4546

@@ -60,7 +61,7 @@ def merge_querysets(cls, default_queryset, queryset):
6061
return queryset & default_queryset
6162

6263
"""
63-
TODO: Not sure this works well or not
64+
TODO: Not sure this works :(
6465
"""
6566
@classmethod
6667
def connection_resolver(cls, resolver, connection, model, root, info, **args):
@@ -83,5 +84,6 @@ def connection_resolver(cls, resolver, connection, model, root, info, **args):
8384
return connection
8485

8586
def get_resolver(self, parent_resolver):
87+
('??')
8688
return partial(self.connection_resolver, parent_resolver, self.type, self.model)
8789

graphene_mongoengine/tests/models.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
MapField, ReferenceField, StringField
88
)
99

10-
connect(host='mongodb://localhost:27017', alias='default')
10+
connect('mongoenginetest', host='mongomock://localhost', alias='default')
11+
1112

1213
class Editor(Document):
1314

1415
meta = {'collection': 'test_editor'}
15-
name = StringField(max_length=16, required=True)
16+
first_name = StringField(required=True)
17+
last_name = StringField(required=True)
1618

1719

1820
class Pet(Document):
@@ -22,7 +24,7 @@ class Pet(Document):
2224
reporter_id = StringField()
2325

2426

25-
class Article(EmbeddedDocument):
27+
class Article(Document):
2628

2729
meta = {'collection': 'test_article'}
2830
headline = StringField(required=True)
@@ -31,13 +33,25 @@ class Article(EmbeddedDocument):
3133
reporter = ReferenceField('Reporter')
3234

3335

36+
class EmbeddedArticle(EmbeddedDocument):
37+
38+
meta = {'collection': 'test_embedded_article'}
39+
headline = StringField(required=True)
40+
pub_date = DateTimeField(default=datetime.now)
41+
editor = ReferenceField(Editor)
42+
reporter = ReferenceField('Reporter')
43+
44+
3445
class Reporter(Document):
3546
meta = {'collection': 'test_repoter'}
3647

3748
first_name = StringField(required=True)
3849
last_name = StringField(requred=True)
3950
email = EmailField()
40-
articles = ListField(EmbeddedDocumentField(Article))
41-
#custom_map = MapField(field=StringField())
51+
articles = ListField(ReferenceField(Article))
52+
# FIXME
53+
# embedded_articles = ListField(EmbeddedDocumentField(EmbeddedArticle))
54+
# FIXME
55+
# custom_map = MapField(field=StringField())
4256
awards = ListField(StringField())
4357

graphene_mongoengine/tests/test_converter.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from py.test import raises
99

10-
from .models import Article, Editor, Reporter
10+
from .models import Article, Editor, EmbeddedArticle, Reporter
1111

1212
from ..converter import convert_mongoengine_field
1313
from ..fields import MongoengineConnectionField
@@ -81,7 +81,7 @@ class Meta:
8181
model = Editor
8282
interfaces = (Node,)
8383

84-
dynamic_field = convert_mongoengine_field(Article._fields['editor'], E._meta.registry)
84+
dynamic_field = convert_mongoengine_field(EmbeddedArticle._fields['editor'], E._meta.registry)
8585
assert isinstance(dynamic_field, Dynamic)
8686
graphene_type = dynamic_field.get_type()
8787
assert isinstance(graphene_type, graphene.Field)
@@ -92,11 +92,10 @@ def test_should_one2many_convert_list():
9292
class A(MongoengineObjectType):
9393
class Meta:
9494
model = Article
95-
interfaces = (Node,)
9695

97-
graphene_field = convert_mongoengine_field(Reporter._fields['articles'].field, A._meta.registry)
98-
assert isinstance(graphene_field, graphene.Dynamic)
96+
graphene_field = convert_mongoengine_field(
97+
Reporter._fields['articles'], A._meta.registry)
98+
assert isinstance(graphene_field, graphene.List)
9999
dynamic_field = graphene_field.get_type()
100-
assert isinstance(dynamic_field, graphene.Field)
101-
assert dynamic_field.type == A
100+
assert dynamic_field._of_type == A
102101

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import json
2+
3+
import graphene
4+
5+
from graphene.relay import Node
6+
7+
from .models import Article, Editor, EmbeddedArticle, Reporter
8+
from ..fields import MongoengineConnectionField
9+
from ..types import MongoengineObjectType
10+
11+
12+
def setup_fixtures():
13+
editor1 = Editor(first_name='Penny', last_name='Hardaway')
14+
editor1.save()
15+
editor2 = Editor(first_name='Grant', last_name='Hill')
16+
editor2.save()
17+
18+
reporter = Reporter(first_name='Allen', last_name='Iverson',
19+
email='[email protected]', awards=['2010-mvp'])
20+
article1 = Article(headline='Hello', editor=editor1)
21+
article1.save()
22+
article2 = Article(headline='World', editor=editor2)
23+
article2.save()
24+
reporter.articles = [article1, article2]
25+
reporter.save()
26+
27+
setup_fixtures()
28+
29+
30+
def test_should_query_editor_well():
31+
class EditorType(MongoengineObjectType):
32+
class Meta:
33+
model = Editor
34+
35+
class Query(graphene.ObjectType):
36+
editor = graphene.Field(EditorType)
37+
editors = graphene.List(EditorType)
38+
39+
def resolve_editor(self, *args, **kwargs):
40+
return Editor.objects.first()
41+
42+
def resolve_editors(self, *args, **kwargs):
43+
return list(Editor.objects.all())
44+
45+
query = '''
46+
query EditorQuery {
47+
editor {
48+
firstName
49+
}
50+
editors {
51+
firstName,
52+
lastName
53+
}
54+
}
55+
'''
56+
expected = {
57+
'editor': {
58+
'firstName': 'Penny'
59+
},
60+
'editors': [{
61+
'firstName': 'Penny',
62+
'lastName': 'Hardaway'
63+
}, {
64+
'firstName': 'Grant',
65+
'lastName': 'Hill'
66+
}]
67+
}
68+
69+
schema = graphene.Schema(query=Query)
70+
result = schema.execute(query)
71+
assert not result.errors
72+
assert dict(result.data['editor']) == expected['editor']
73+
assert all(item in result.data['editors'] for item in expected['editors'])
74+
75+
76+
def test_should_query_reporter_well():
77+
class ArticleType(MongoengineObjectType):
78+
class Meta:
79+
model = Article
80+
81+
class ReporterType(MongoengineObjectType):
82+
class Meta:
83+
model = Reporter
84+
85+
class Query(graphene.ObjectType):
86+
reporter = graphene.Field(ReporterType)
87+
88+
def resolve_reporter(self, *args, **kwargs):
89+
return Reporter.objects.first()
90+
91+
query = '''
92+
query ReporterQuery {
93+
reporter {
94+
firstName,
95+
lastName,
96+
email,
97+
articles {
98+
headline
99+
},
100+
awards
101+
}
102+
}
103+
'''
104+
expected = {
105+
'reporter': {
106+
'firstName': 'Allen',
107+
'lastName': 'Iverson',
108+
'email': '[email protected]',
109+
'articles': [
110+
{'headline': 'Hello'},
111+
{'headline': 'World'}
112+
],
113+
'awards': ['2010-mvp']
114+
}
115+
}
116+
117+
schema = graphene.Schema(query=Query)
118+
result = schema.execute(query)
119+
assert not result.errors
120+
assert dict(result.data['reporter']) == expected['reporter']
121+
122+
def test_should_node():
123+
class ArticleNode(MongoengineObjectType):
124+
class Meta:
125+
model = Article
126+
interfaces = (Node,)
127+
128+
class ReporterNode(MongoengineObjectType):
129+
class Meta:
130+
model = Reporter
131+
interfaces = (Node,)
132+
133+
class Query(graphene.ObjectType):
134+
node = Node.Field()
135+
reporter = graphene.Field(ReporterNode)
136+
137+
def resolve_reporter(self, *args, **kwargs):
138+
return Reporter.objects.first()
139+
140+
query = '''
141+
query ReporterQuery {
142+
reporter {
143+
firstName,
144+
articles {
145+
edges {
146+
node {
147+
headline
148+
}
149+
}
150+
}
151+
lastName,
152+
email
153+
}
154+
}
155+
'''
156+
expected = {
157+
'reporter': {
158+
'firstName': 'Allen',
159+
'lastName': 'Iverson',
160+
'articles': {
161+
'edges': [
162+
{
163+
'node': {
164+
'headline': 'Hello'
165+
}
166+
},
167+
{
168+
'node': {
169+
'headline': 'World'
170+
}
171+
}
172+
],
173+
},
174+
'email': '[email protected]'
175+
}
176+
}
177+
178+
schema = graphene.Schema(query=Query)
179+
result = schema.execute(query)
180+
assert not result.errors
181+
assert dict(result.data['reporter']) == expected['reporter']
182+
183+
# TODO:
184+
def test_should_custom_identifier():
185+
pass
186+
187+
# TODO:
188+
def test_should_mutate_well():
189+
pass
190+
191+
# TODO:
192+
def test_should_filter():
193+
pass
194+
195+
# TODO:
196+
def test_should_paging():
197+
pass
198+

graphene_mongoengine/tests/test_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def test_objecttype_registered():
4040
'first_name',
4141
'last_name',
4242
'email',
43+
# FIXME
44+
# 'embedded_articles',
4345
'articles',
4446
'awards'
4547
])

graphene_mongoengine/types.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ def __init_subclass_with_meta__(cls, model=None, registry=None, skip_registry=Fa
7979
_meta.registry = registry
8080
_meta.fields = mongoengine_fields
8181
_meta.connection = connection
82-
8382
super(MongoengineObjectType, cls).__init_subclass_with_meta__(
8483
_meta=_meta, interfaces=interfaces, **options
8584
)
@@ -91,7 +90,7 @@ def __init_subclass_with_meta__(cls, model=None, registry=None, skip_registry=Fa
9190
def is_type_of(cls, root, info):
9291
if isinstance(root, cls):
9392
return True
94-
if not is_mapped_instance(root):
93+
if not is_valid_mongoengine_model(type(root)):
9594
raise Exception((
9695
'Received incompatible instance "{}".'
9796
).format(root))
@@ -101,13 +100,13 @@ def is_type_of(cls, root, info):
101100
def get_node(cls, id, context, info):
102101
if isinstance(getattr(cls._meta.model, get_key_name(cls._meta.model)), NumberAttribute):
103102
return cls._meta.model.get(int(id))
104-
else:
105-
return cls._meta.model.get(id)
103+
104+
return cls._meta.model.get(id)
106105

107106
def resolve_id(self, info):
108107
return str(self.id)
109108

110-
@classmethod
111-
def get_connection(cls):
112-
return connection_for_type(cls)
109+
#@classmethod
110+
#def get_connection(cls):
111+
# return connection_for_type(cls)
113112

0 commit comments

Comments
 (0)