Skip to content
This repository was archived by the owner on Sep 6, 2022. It is now read-only.

Commit 4ee421c

Browse files
committed
Merge pull request #11 from graphql-python/feature/support_computed_and_localstructure_fields
LocalStructuredProperty support
2 parents 0e12eb2 + 7bd8540 commit 4ee421c

File tree

7 files changed

+144
-4
lines changed

7 files changed

+144
-4
lines changed

graphene_gae/ndb/converter.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import inflect
44
from google.appengine.ext import ndb
55

6+
from graphene import LazyType
7+
from graphene.core.types import Field
8+
from graphene.core.types.definitions import List
69
from graphene.core.types.scalars import String, Boolean, Int, Float
710
from graphene.core.types.custom_scalars import JSONString, DateTime
811
from graphene_gae.ndb.fields import NdbKeyField
@@ -65,6 +68,20 @@ def convert_ndb_key_propety(ndb_key_prop, meta):
6568
return ConversionResult(name=name, field=field)
6669

6770

71+
def convert_local_structured_property(ndb_structured_prop, meta):
72+
is_required = ndb_structured_prop._required
73+
is_repeated = ndb_structured_prop._repeated
74+
model = ndb_structured_prop._modelclass
75+
name = ndb_structured_prop._code_name
76+
77+
t = LazyType(model.__name__ + 'Type')
78+
if is_repeated:
79+
l = List(t)
80+
return ConversionResult(name=name, field=l.NonNull if is_required else l)
81+
82+
return ConversionResult(name=name, field=Field(t))
83+
84+
6885
converters = {
6986
ndb.StringProperty: convert_ndb_string_property,
7087
ndb.TextProperty: convert_ndb_string_property,
@@ -74,7 +91,8 @@ def convert_ndb_key_propety(ndb_key_prop, meta):
7491
ndb.JsonProperty: convert_ndb_json_property,
7592
ndb.DateProperty: convert_ndb_datetime_property,
7693
ndb.DateTimeProperty: convert_ndb_datetime_property,
77-
ndb.KeyProperty: convert_ndb_key_propety
94+
ndb.KeyProperty: convert_ndb_key_propety,
95+
ndb.LocalStructuredProperty: convert_local_structured_property
7896
}
7997

8098

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
pip
2+
setuptools
3+
14
wheel==0.23.0
25
tox
36
coverage

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ def get_version(package_name):
5353
'PyYAML==3.11',
5454
'webapp2==2.5.2',
5555
'webob==1.2.3',
56-
'WebTest==2.0.11'
56+
'WebTest==2.0.11',
57+
'mock'
5758
]
5859

5960

tests/_ndb/test_converter.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import mock
12
from tests.base_test import BaseTest
23

34
from google.appengine.ext import ndb
@@ -29,6 +30,17 @@ def testUnknownProperty_raisesException(self):
2930

3031
self.assertTrue("Don't know how to convert" in context.exception.message, msg=context.exception.message)
3132

33+
@mock.patch('graphene_gae.ndb.converter.converters')
34+
def testNoneResult_raisesException(self, patch_convert):
35+
from graphene_gae.ndb.converter import convert_ndb_property
36+
patch_convert.get.return_value = lambda _, __: None
37+
with self.assertRaises(Exception) as context:
38+
prop = ndb.StringProperty()
39+
prop._code_name = "my_prop"
40+
convert_ndb_property(prop)
41+
42+
self.assertTrue("Failed to convert NDB field my_prop" in context.exception.message, msg=context.exception.message)
43+
3244
def testStringProperty_shouldConvertToString(self):
3345
self.__assert_conversion(ndb.StringProperty, graphene.String)
3446

tests/_ndb/test_types.py

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,31 @@
33
import graphene
44

55
from graphene_gae import NdbObjectType
6-
from tests.models import Tag, Comment, Article
6+
from tests.models import Tag, Comment, Article, Address, Author, PhoneNumber
77

88
__author__ = 'ekampf'
99

1010
schema = graphene.Schema()
1111

1212

13+
@schema.register
14+
class AddressType(NdbObjectType):
15+
class Meta:
16+
model = Address
17+
18+
19+
@schema.register
20+
class PhoneNumberType(NdbObjectType):
21+
class Meta:
22+
model = PhoneNumber
23+
24+
25+
@schema.register
26+
class AuthorType(NdbObjectType):
27+
class Meta:
28+
model = Author
29+
30+
1331
@schema.register
1432
class TagType(NdbObjectType):
1533
class Meta:
@@ -169,3 +187,66 @@ def testQuery_repeatedProperty(self):
169187
self.assertEqual(article["createdAt"], str(a.get().created_at.isoformat()))
170188
self.assertEqual(article["headline"], "Test1")
171189
self.assertListEqual(article["keywords"], keywords)
190+
191+
def testQuery_structuredProperty(self):
192+
mobile = PhoneNumber(area="650", number="12345678")
193+
author_key = Author(name="John Dow", email="[email protected]", mobile=mobile).put()
194+
Article(headline="Test1", author_key=author_key).put()
195+
196+
result = schema.execute("""
197+
query Articles {
198+
articles {
199+
headline,
200+
author {
201+
name
202+
email
203+
mobile { area, number }
204+
}
205+
}
206+
}
207+
""")
208+
self.assertEmpty(result.errors, msg=str(result.errors))
209+
210+
article = result.data['articles'][0]
211+
self.assertEqual(article["headline"], "Test1")
212+
213+
author = article['author']
214+
self.assertEqual(author["name"], "John Dow")
215+
self.assertEqual(author["email"], "[email protected]")
216+
self.assertDictEqual(dict(area="650", number="12345678"), dict(author["mobile"]))
217+
218+
def testQuery_structuredProperty_repeated(self):
219+
address1 = Address(address1="address1", address2="apt 1", city="Mountain View")
220+
address2 = Address(address1="address2", address2="apt 2", city="Mountain View")
221+
author_key = Author(name="John Dow", email="[email protected]", addresses=[address1, address2]).put()
222+
Article(headline="Test1", author_key=author_key).put()
223+
224+
result = schema.execute("""
225+
query Articles {
226+
articles {
227+
headline,
228+
author {
229+
name
230+
email
231+
addresses {
232+
address1
233+
address2
234+
city
235+
}
236+
}
237+
}
238+
}
239+
""")
240+
self.assertEmpty(result.errors)
241+
242+
article = result.data['articles'][0]
243+
self.assertEqual(article["headline"], "Test1")
244+
245+
author = article['author']
246+
self.assertEqual(author["name"], "John Dow")
247+
self.assertEqual(author["email"], "[email protected]")
248+
self.assertLength(author["addresses"], 2)
249+
250+
addresses = [dict(d) for d in author["addresses"]]
251+
self.assertIn(address1.to_dict(), addresses)
252+
self.assertIn(address2.to_dict(), addresses)

tests/_ndb/test_types_relay.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,26 @@
55
import graphene
66
from graphene_gae import NdbNode, NdbConnectionField
77

8-
from tests.models import Tag, Comment, Article, Author
8+
from tests.models import Tag, Comment, Article, Author, Address, PhoneNumber
99

1010
__author__ = 'ekampf'
1111

1212

1313
schema = graphene.Schema()
1414

1515

16+
@schema.register
17+
class AddressType(NdbNode):
18+
class Meta:
19+
model = Address
20+
21+
22+
@schema.register
23+
class PhoneNumberType(NdbNode):
24+
class Meta:
25+
model = PhoneNumber
26+
27+
1628
@schema.register
1729
class AuthorType(NdbNode):
1830
class Meta:

tests/models.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,22 @@
33
__author__ = 'ekampf'
44

55

6+
class Address(ndb.Model):
7+
address1 = ndb.StringProperty()
8+
address2 = ndb.StringProperty()
9+
city = ndb.StringProperty()
10+
11+
12+
class PhoneNumber(ndb.Model):
13+
area = ndb.StringProperty()
14+
number = ndb.StringProperty()
15+
16+
617
class Author(ndb.Model):
718
name = ndb.StringProperty()
819
email = ndb.StringProperty()
20+
addresses = ndb.LocalStructuredProperty(Address, repeated=True)
21+
mobile = ndb.LocalStructuredProperty(PhoneNumber)
922

1023

1124
class Tag(ndb.Model):

0 commit comments

Comments
 (0)