Skip to content

Commit 72a2610

Browse files
Merge pull request #1 from graphql-python/master
Sync
2 parents fe51fc6 + 1d6a933 commit 72a2610

23 files changed

+1479
-467
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
language: python
22
python:
33
- "2.7"
4-
- "3.3"
54
- "3.4"
65
- "3.5"
76
- "3.6"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[![Build Status](https://travis-ci.org/graphql-python/graphene-mongo.svg?branch=master)](https://travis-ci.org/graphql-python/graphene-mongo) [![Coverage Status](https://coveralls.io/repos/github/graphql-python/graphene-mongo/badge.svg?branch=master)](https://coveralls.io/github/graphql-python/graphene-mongo?branch=master) [![Documentation Status](https://readthedocs.org/projects/graphene-mongo/badge/?version=latest)](http://graphene-mongo.readthedocs.io/en/latest/?badge=latest) [![PyPI version](https://badge.fury.io/py/graphene-mongo.svg)](https://badge.fury.io/py/graphene-mongo) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/graphene-mongo.svg)](https://pypi.python.org/pypi/graphene-mongo/)
1+
[![Build Status](https://travis-ci.org/graphql-python/graphene-mongo.svg?branch=master)](https://travis-ci.org/graphql-python/graphene-mongo) [![Coverage Status](https://coveralls.io/repos/github/graphql-python/graphene-mongo/badge.svg?branch=master)](https://coveralls.io/github/graphql-python/graphene-mongo?branch=master) [![Documentation Status](https://readthedocs.org/projects/graphene-mongo/badge/?version=latest)](http://graphene-mongo.readthedocs.io/en/latest/?badge=latest) [![PyPI version](https://badge.fury.io/py/graphene-mongo.svg)](https://badge.fury.io/py/graphene-mongo) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/graphene-mongo.svg)](https://pypi.python.org/pypi/graphene-mongo/) [![Downloads](https://pepy.tech/badge/graphene-mongo)](https://pepy.tech/project/graphene-mongo)
22

33
# Graphene-Mongo
44

docs/fields.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ Mongoengine Fields
1111
- EmailField
1212
- EmbeddedDocumentField
1313
- EmbeddedDocumentListField
14+
- FileField
1415
- FloatField
15-
- IntegerField
16+
- GenericReferenceField
17+
- IntField
1618
- ListField
1719
- ObjectIdField
1820
- ReferenceField
21+
- PointField
22+
- PolygonField
1923
- StringField
2024
- URLField
2125
- UUIDField
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Flask==0.12.2
2-
Flask-GraphQL==1.4.1
2+
Flask-GraphQL==2.0.0
33
graphene-mongo
4-
mongomock==3.8.0
4+
mongomock==3.14.0
55

graphene_mongo/advanced_types.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import base64
2+
import graphene
3+
4+
5+
class FileFieldType(graphene.ObjectType):
6+
7+
content_type = graphene.String()
8+
md5 = graphene.String()
9+
chunk_size = graphene.Int()
10+
length = graphene.Int()
11+
data = graphene.String()
12+
13+
@classmethod
14+
def _resolve_fs_field(cls, field, name, default_value=None):
15+
v = getattr(field.instance, field.key)
16+
return getattr(v, name, default_value)
17+
18+
def resolve_content_type(self, info):
19+
return FileFieldType._resolve_fs_field(self, 'content_type')
20+
21+
def resolve_md5(self, info):
22+
return FileFieldType._resolve_fs_field(self, 'md5')
23+
24+
def resolve_chunk_size(self, info):
25+
return FileFieldType._resolve_fs_field(self, 'chunk_size', 0)
26+
27+
def resolve_length(self, info):
28+
return FileFieldType._resolve_fs_field(self, 'length', 0)
29+
30+
def resolve_data(self, info):
31+
v = getattr(self.instance, self.key)
32+
data = v.read()
33+
if data is not None:
34+
return base64.b64encode(data)
35+
return None
36+
37+
38+
class _CoordinatesTypeField(graphene.ObjectType):
39+
40+
type = graphene.String()
41+
42+
def resolve_type(self, info):
43+
return self['type']
44+
45+
def resolve_coordinates(self, info):
46+
return self['coordinates']
47+
48+
49+
class PointFieldType(_CoordinatesTypeField):
50+
51+
coordinates = graphene.List(graphene.Float)
52+
53+
54+
class PolygonFieldType(_CoordinatesTypeField):
55+
56+
coordinates = graphene.List(
57+
graphene.List(
58+
graphene.List(graphene.Float))
59+
)
60+
61+
62+
class MultiPolygonFieldType(_CoordinatesTypeField):
63+
64+
coordinates = graphene.List(
65+
graphene.List(
66+
graphene.List(
67+
graphene.List(graphene.Float)))
68+
)

graphene_mongo/converter.py

Lines changed: 104 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,37 @@
1-
from graphene import (ID, Boolean, Dynamic, Field, Float, Int, List,
2-
NonNull, String, is_node)
3-
from graphene.types.json import JSONString
4-
51
import mongoengine
2+
import uuid
3+
from graphene import (
4+
ID,
5+
Boolean,
6+
DateTime,
7+
Dynamic,
8+
Field,
9+
Float,
10+
Int,
11+
List,
12+
NonNull,
13+
String,
14+
Union,
15+
is_node
16+
)
17+
from graphene.types.json import JSONString
18+
from mongoengine.base import get_document
619

7-
from .fields import MongoengineConnectionField
8-
from .utils import import_single_dispatch
20+
from . import advanced_types
21+
from .utils import (
22+
import_single_dispatch, get_field_description,
23+
)
924

1025
singledispatch = import_single_dispatch()
1126

1227

28+
class MongoEngineConversionError(Exception):
29+
pass
30+
31+
1332
@singledispatch
1433
def convert_mongoengine_field(field, registry=None):
15-
raise Exception(
34+
raise MongoEngineConversionError(
1635
"Don't know how to convert the MongoEngine field %s (%s)" %
1736
(field, field.__class__))
1837

@@ -21,41 +40,61 @@ def convert_mongoengine_field(field, registry=None):
2140
@convert_mongoengine_field.register(mongoengine.StringField)
2241
@convert_mongoengine_field.register(mongoengine.URLField)
2342
def convert_field_to_string(field, registry=None):
24-
return String(description=field.db_field, required=field.required)
43+
return String(description=get_field_description(field, registry), required=field.required)
2544

2645

2746
@convert_mongoengine_field.register(mongoengine.UUIDField)
2847
@convert_mongoengine_field.register(mongoengine.ObjectIdField)
2948
def convert_field_to_id(field, registry=None):
30-
return ID(description=field.db_field, required=field.required)
49+
return ID(description=get_field_description(field, registry), required=field.required)
3150

3251

3352
@convert_mongoengine_field.register(mongoengine.IntField)
3453
@convert_mongoengine_field.register(mongoengine.LongField)
3554
def convert_field_to_int(field, registry=None):
36-
return Int(description=field.db_field, required=field.required)
55+
return Int(description=get_field_description(field, registry), required=field.required)
3756

3857

3958
@convert_mongoengine_field.register(mongoengine.BooleanField)
4059
def convert_field_to_boolean(field, registry=None):
41-
return Boolean(description=field.db_field, required=field.required)
60+
return Boolean(description=get_field_description(field, registry), required=field.required)
4261

4362

4463
@convert_mongoengine_field.register(mongoengine.DecimalField)
4564
@convert_mongoengine_field.register(mongoengine.FloatField)
4665
def convert_field_to_float(field, registry=None):
47-
return Float(description=field.db_field, required=field.required)
66+
return Float(description=get_field_description(field, registry), required=field.required)
67+
68+
69+
@convert_mongoengine_field.register(mongoengine.DateTimeField)
70+
def convert_field_to_datetime(field, registry=None):
71+
return DateTime(description=get_field_description(field, registry), required=field.required)
4872

4973

5074
@convert_mongoengine_field.register(mongoengine.DictField)
5175
@convert_mongoengine_field.register(mongoengine.MapField)
52-
def convert_dict_to_jsonstring(field, registry=None):
53-
return JSONString(description=field.db_field, required=field.required)
76+
def convert_field_to_jsonstring(field, registry=None):
77+
return JSONString(description=get_field_description(field, registry), required=field.required)
5478

5579

56-
@convert_mongoengine_field.register(mongoengine.DateTimeField)
57-
def convert_date_to_string(field, registry=None):
58-
return String(description=field.db_field, required=field.required)
80+
@convert_mongoengine_field.register(mongoengine.PointField)
81+
def convert_point_to_field(field, registry=None):
82+
return Field(advanced_types.PointFieldType)
83+
84+
85+
@convert_mongoengine_field.register(mongoengine.PolygonField)
86+
def convert_polygon_to_field(field, registry=None):
87+
return Field(advanced_types.PolygonFieldType)
88+
89+
90+
@convert_mongoengine_field.register(mongoengine.MultiPolygonField)
91+
def convert_multipolygon_to_field(field, register=None):
92+
return Field(advanced_types.MultiPolygonFieldType)
93+
94+
95+
@convert_mongoengine_field.register(mongoengine.FileField)
96+
def convert_file_to_field(field, registry=None):
97+
return Field(advanced_types.FileFieldType)
5998

6099

61100
@convert_mongoengine_field.register(mongoengine.ListField)
@@ -69,15 +108,43 @@ def convert_field_to_list(field, registry=None):
69108
base_type = base_type._type
70109

71110
if is_node(base_type):
72-
return MongoengineConnectionField(base_type)
111+
return base_type._meta.connection_field_class(base_type)
73112

74113
# Non-relationship field
75114
relations = (mongoengine.ReferenceField, mongoengine.EmbeddedDocumentField)
76115
if not isinstance(base_type, (List, NonNull)) \
77116
and not isinstance(field.field, relations):
78117
base_type = type(base_type)
79118

80-
return List(base_type, description=field.db_field, required=field.required)
119+
return List(base_type, description=get_field_description(field, registry), required=field.required)
120+
121+
122+
@convert_mongoengine_field.register(mongoengine.GenericReferenceField)
123+
def convert_field_to_union(field, registry=None):
124+
125+
_types = []
126+
for choice in field.choices:
127+
_field = mongoengine.ReferenceField(get_document(choice))
128+
_field = convert_mongoengine_field(_field, registry)
129+
_type = _field.get_type()
130+
if _type:
131+
_types.append(_type.type)
132+
else:
133+
# TODO: Register type auto-matically here.
134+
pass
135+
136+
if len(_types) == 0:
137+
return None
138+
139+
# XXX: Use uuid to avoid duplicate name
140+
name = '{}_{}_union_{}'.format(
141+
field._owner_document.__name__,
142+
field.db_field,
143+
str(uuid.uuid1()).replace('-', '')
144+
)
145+
Meta = type('Meta', (object, ), {'types': tuple(_types)})
146+
_union = type(name, (Union, ), {'Meta': Meta})
147+
return Field(_union)
81148

82149

83150
@convert_mongoengine_field.register(mongoengine.EmbeddedDocumentField)
@@ -89,6 +156,23 @@ def dynamic_type():
89156
_type = registry.get_type_for_model(model)
90157
if not _type:
91158
return None
92-
return Field(_type)
159+
return Field(_type, description=get_field_description(field, registry))
160+
161+
return Dynamic(dynamic_type)
162+
163+
164+
@convert_mongoengine_field.register(mongoengine.LazyReferenceField)
165+
def convert_lazy_field_to_dynamic(field, registry=None):
166+
model = field.document_type
167+
168+
def lazy_resolver(root, *args, **kwargs):
169+
if getattr(root, field.name or field.db_name):
170+
return getattr(root, field.name or field.db_name).fetch()
171+
172+
def dynamic_type():
173+
_type = registry.get_type_for_model(model)
174+
if not _type:
175+
return None
176+
return Field(_type, resolver=lazy_resolver, description=get_field_description(field, registry))
93177

94178
return Dynamic(dynamic_type)

0 commit comments

Comments
 (0)