Skip to content

Commit 4827ce2

Browse files
authored
Merge pull request #78 from Cito/convert_enums
Proper support for the SQLAlchemy Enum type
2 parents cad0894 + 2fac056 commit 4827ce2

File tree

4 files changed

+87
-14
lines changed

4 files changed

+87
-14
lines changed

graphene_sqlalchemy/converter.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ def convert_sqlalchemy_type(type, column, registry=None):
9191
@convert_sqlalchemy_type.register(types.Text)
9292
@convert_sqlalchemy_type.register(types.Unicode)
9393
@convert_sqlalchemy_type.register(types.UnicodeText)
94-
@convert_sqlalchemy_type.register(types.Enum)
95-
@convert_sqlalchemy_type.register(postgresql.ENUM)
9694
@convert_sqlalchemy_type.register(postgresql.UUID)
9795
@convert_sqlalchemy_type.register(TSVectorType)
9896
def convert_column_to_string(type, column, registry=None):
@@ -111,22 +109,36 @@ def convert_column_to_datetime(type, column, registry=None):
111109
@convert_sqlalchemy_type.register(types.Integer)
112110
def convert_column_to_int_or_id(type, column, registry=None):
113111
if column.primary_key:
114-
return ID(description=get_column_doc(column), required=not (is_column_nullable(column)))
112+
return ID(description=get_column_doc(column),
113+
required=not (is_column_nullable(column)))
115114
else:
116115
return Int(description=get_column_doc(column),
117116
required=not (is_column_nullable(column)))
118117

119118

120119
@convert_sqlalchemy_type.register(types.Boolean)
121120
def convert_column_to_boolean(type, column, registry=None):
122-
return Boolean(description=get_column_doc(column), required=not(is_column_nullable(column)))
121+
return Boolean(description=get_column_doc(column),
122+
required=not(is_column_nullable(column)))
123123

124124

125125
@convert_sqlalchemy_type.register(types.Float)
126126
@convert_sqlalchemy_type.register(types.Numeric)
127127
@convert_sqlalchemy_type.register(types.BigInteger)
128128
def convert_column_to_float(type, column, registry=None):
129-
return Float(description=get_column_doc(column), required=not(is_column_nullable(column)))
129+
return Float(description=get_column_doc(column),
130+
required=not(is_column_nullable(column)))
131+
132+
133+
@convert_sqlalchemy_type.register(types.Enum)
134+
def convert_enum_to_enum(type, column, registry=None):
135+
try:
136+
items = type.enum_class.__members__.items()
137+
except AttributeError:
138+
items = zip(type.enums, type.enums)
139+
return Field(Enum(type.name, items),
140+
description=get_column_doc(column),
141+
required=not(is_column_nullable(column)))
130142

131143

132144
@convert_sqlalchemy_type.register(ChoiceType)
@@ -144,16 +156,19 @@ def convert_scalar_list_to_list(type, column, registry=None):
144156
def convert_postgres_array_to_list(_type, column, registry=None):
145157
graphene_type = convert_sqlalchemy_type(column.type.item_type, column)
146158
inner_type = type(graphene_type)
147-
return List(inner_type, description=get_column_doc(column), required=not(is_column_nullable(column)))
159+
return List(inner_type, description=get_column_doc(column),
160+
required=not(is_column_nullable(column)))
148161

149162

150163
@convert_sqlalchemy_type.register(postgresql.HSTORE)
151164
@convert_sqlalchemy_type.register(postgresql.JSON)
152165
@convert_sqlalchemy_type.register(postgresql.JSONB)
153166
def convert_json_to_string(type, column, registry=None):
154-
return JSONString(description=get_column_doc(column), required=not(is_column_nullable(column)))
167+
return JSONString(description=get_column_doc(column),
168+
required=not(is_column_nullable(column)))
155169

156170

157171
@convert_sqlalchemy_type.register(JSONType)
158172
def convert_json_type_to_string(type, column, registry=None):
159-
return JSONString(description=get_column_doc(column), required=not(is_column_nullable(column)))
173+
return JSONString(description=get_column_doc(column),
174+
required=not(is_column_nullable(column)))

graphene_sqlalchemy/tests/models.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from __future__ import absolute_import
22

3-
from sqlalchemy import Column, Date, ForeignKey, Integer, String, Table
3+
import enum
4+
5+
from sqlalchemy import Column, Date, Enum, ForeignKey, Integer, String, Table
46
from sqlalchemy.ext.declarative import declarative_base
57
from sqlalchemy.orm import mapper, relationship
68

@@ -21,6 +23,7 @@ class Pet(Base):
2123
__tablename__ = 'pets'
2224
id = Column(Integer(), primary_key=True)
2325
name = Column(String(30))
26+
pet_kind = Column(Enum('cat', 'dog', name='pet_kind'), nullable=False)
2427
reporter_id = Column(Integer(), ForeignKey('reporters.id'))
2528

2629

graphene_sqlalchemy/tests/test_converter.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import enum
2+
13
from py.test import raises
24
from sqlalchemy import Column, Table, case, types, select, func
35
from sqlalchemy.dialects import postgresql
@@ -24,7 +26,8 @@ def assert_column_conversion(sqlalchemy_type, graphene_field, **kwargs):
2426
column = Column(sqlalchemy_type, doc='Custom Help Text', **kwargs)
2527
graphene_type = convert_sqlalchemy_column(column)
2628
assert isinstance(graphene_type, graphene_field)
27-
field = graphene_type.Field()
29+
field = graphene_type if isinstance(
30+
graphene_type, graphene.Field) else graphene_type.Field()
2831
assert field.description == 'Custom Help Text'
2932
return field
3033

@@ -76,8 +79,18 @@ def test_should_unicodetext_convert_string():
7679
assert_column_conversion(types.UnicodeText(), graphene.String)
7780

7881

79-
def test_should_enum_convert_string():
80-
assert_column_conversion(types.Enum(), graphene.String)
82+
def test_should_enum_convert_enum():
83+
field = assert_column_conversion(
84+
types.Enum(enum.Enum('one', 'two')), graphene.Field)
85+
field_type = field.type()
86+
assert isinstance(field_type, graphene.Enum)
87+
assert hasattr(field_type, 'two')
88+
field = assert_column_conversion(
89+
types.Enum('one', 'two', name='two_numbers'), graphene.Field)
90+
field_type = field.type()
91+
assert field_type.__class__.__name__ == 'two_numbers'
92+
assert isinstance(field_type, graphene.Enum)
93+
assert hasattr(field_type, 'two')
8194

8295

8396
def test_should_small_integer_convert_int():
@@ -119,6 +132,7 @@ def test_should_label_convert_int():
119132
graphene_type = convert_sqlalchemy_column(label)
120133
assert isinstance(graphene_type, graphene.Int)
121134

135+
122136
def test_should_choice_convert_enum():
123137
TYPES = [
124138
(u'es', u'Spanish'),
@@ -247,7 +261,12 @@ def test_should_postgresql_uuid_convert():
247261

248262

249263
def test_should_postgresql_enum_convert():
250-
assert_column_conversion(postgresql.ENUM(), graphene.String)
264+
field = assert_column_conversion(postgresql.ENUM(
265+
enum.Enum('one', 'two'), name='two_numbers'), graphene.Field)
266+
field_type = field.type()
267+
assert field_type.__class__.__name__ == 'two_numbers'
268+
assert isinstance(field_type, graphene.Enum)
269+
assert hasattr(field_type, 'two')
251270

252271

253272
def test_should_postgresql_array_convert():

graphene_sqlalchemy/tests/test_query.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from ..registry import reset_global_registry
99
from ..fields import SQLAlchemyConnectionField
1010
from ..types import SQLAlchemyObjectType
11-
from .models import Article, Base, Editor, Reporter
11+
from .models import Article, Base, Editor, Pet, Reporter
1212

1313
db = create_engine('sqlite:///test_sqlalchemy.sqlite3')
1414

@@ -33,6 +33,8 @@ def session():
3333

3434

3535
def setup_fixtures(session):
36+
pet = Pet(name='Lassie', pet_kind='dog')
37+
session.add(pet)
3638
reporter = Reporter(first_name='ABA', last_name='X')
3739
session.add(reporter)
3840
reporter2 = Reporter(first_name='ABO', last_name='Y')
@@ -93,6 +95,40 @@ def resolve_reporters(self, *args, **kwargs):
9395
assert result.data == expected
9496

9597

98+
def test_should_query_enums(session):
99+
setup_fixtures(session)
100+
101+
class PetType(SQLAlchemyObjectType):
102+
103+
class Meta:
104+
model = Pet
105+
106+
class Query(graphene.ObjectType):
107+
pet = graphene.Field(PetType)
108+
109+
def resolve_pet(self, *args, **kwargs):
110+
return session.query(Pet).first()
111+
112+
query = '''
113+
query PetQuery {
114+
pet {
115+
name,
116+
petKind
117+
}
118+
}
119+
'''
120+
expected = {
121+
'pet': {
122+
'name': 'Lassie',
123+
'petKind': 'dog'
124+
}
125+
}
126+
schema = graphene.Schema(query=Query)
127+
result = schema.execute(query)
128+
assert not result.errors
129+
assert result.data == expected, result.data
130+
131+
96132
def test_should_node(session):
97133
setup_fixtures(session)
98134

0 commit comments

Comments
 (0)