Improved SQLAlchemy integration

This commit is contained in:
Syrus Akbary 2016-08-15 23:46:30 -07:00
parent e5831057f0
commit 13f9b658c1
3 changed files with 50 additions and 43 deletions

View File

@ -55,7 +55,7 @@ def convert_sqlalchemy_type(type, column, registry=None):
@convert_sqlalchemy_type.register(postgresql.ENUM) @convert_sqlalchemy_type.register(postgresql.ENUM)
@convert_sqlalchemy_type.register(postgresql.UUID) @convert_sqlalchemy_type.register(postgresql.UUID)
def convert_column_to_string(type, column, registry=None): def convert_column_to_string(type, column, registry=None):
return String(description=column.doc) return String(description=column.doc, required=not(column.nullable))
@convert_sqlalchemy_type.register(types.SmallInteger) @convert_sqlalchemy_type.register(types.SmallInteger)
@ -63,20 +63,20 @@ def convert_column_to_string(type, column, registry=None):
@convert_sqlalchemy_type.register(types.Integer) @convert_sqlalchemy_type.register(types.Integer)
def convert_column_to_int_or_id(type, column, registry=None): def convert_column_to_int_or_id(type, column, registry=None):
if column.primary_key: if column.primary_key:
return ID(description=column.doc) return ID(description=column.doc, required=not(column.nullable))
else: else:
return Int(description=column.doc) return Int(description=column.doc, required=not(column.nullable))
@convert_sqlalchemy_type.register(types.Boolean) @convert_sqlalchemy_type.register(types.Boolean)
def convert_column_to_boolean(type, column, registry=None): def convert_column_to_boolean(type, column, registry=None):
return Boolean(description=column.doc) return Boolean(description=column.doc, required=not(column.nullable))
@convert_sqlalchemy_type.register(types.Float) @convert_sqlalchemy_type.register(types.Float)
@convert_sqlalchemy_type.register(types.Numeric) @convert_sqlalchemy_type.register(types.Numeric)
def convert_column_to_float(type, column, registry=None): def convert_column_to_float(type, column, registry=None):
return Float(description=column.doc) return Float(description=column.doc, required=not(column.nullable))
@convert_sqlalchemy_type.register(ChoiceType) @convert_sqlalchemy_type.register(ChoiceType)
@ -88,11 +88,11 @@ def convert_column_to_enum(type, column, registry=None):
@convert_sqlalchemy_type.register(postgresql.ARRAY) @convert_sqlalchemy_type.register(postgresql.ARRAY)
def convert_postgres_array_to_list(type, column, registry=None): def convert_postgres_array_to_list(type, column, registry=None):
graphene_type = convert_sqlalchemy_type(column.type.item_type, column) graphene_type = convert_sqlalchemy_type(column.type.item_type, column)
return List(graphene_type, description=column.doc) return List(graphene_type, description=column.doc, required=not(column.nullable))
@convert_sqlalchemy_type.register(postgresql.HSTORE) @convert_sqlalchemy_type.register(postgresql.HSTORE)
@convert_sqlalchemy_type.register(postgresql.JSON) @convert_sqlalchemy_type.register(postgresql.JSON)
@convert_sqlalchemy_type.register(postgresql.JSONB) @convert_sqlalchemy_type.register(postgresql.JSONB)
def convert_json_to_string(type, column, registry=None): def convert_json_to_string(type, column, registry=None):
return JSONString(description=column.doc) return JSONString(description=column.doc, required=not(column.nullable))

View File

@ -70,5 +70,5 @@ def test_node_replacedfield():
def test_object_type(): def test_object_type():
assert issubclass(Human, ObjectType) assert issubclass(Human, ObjectType)
assert list(Human._meta.fields.keys()) == ['id', 'pub_date', 'headline', 'reporter_id', 'reporter'] assert list(Human._meta.fields.keys()) == ['id', 'headline', 'reporter_id', 'reporter', 'pub_date']
assert is_node(Human) assert is_node(Human)

View File

@ -13,43 +13,45 @@ from graphene.types.objecttype import ObjectTypeMeta
from graphene.types.options import Options from graphene.types.options import Options
from .registry import Registry, get_global_registry from .registry import Registry, get_global_registry
from graphene.utils.is_base_type import is_base_type from graphene.utils.is_base_type import is_base_type
from graphene.types.utils import get_fields_in_type from graphene.types.utils import get_fields_in_type, merge
from .utils import get_query from .utils import get_query
def construct_fields(options):
only_fields = options.only_fields
exclude_fields = options.exclude_fields
inspected_model = sqlalchemyinspect(options.model)
fields = OrderedDict()
for name, column in inspected_model.columns.items():
is_not_in_only = only_fields and name not in only_fields
is_already_created = name in options.fields
is_excluded = name in exclude_fields or is_already_created
if is_not_in_only or is_excluded:
# We skip this field if we specify only_fields and is not
# in there. Or when we excldue this field in exclude_fields
continue
converted_column = convert_sqlalchemy_column(column, options.registry)
fields[name] = converted_column
# Get all the columns for the relationships on the model
for relationship in inspected_model.relationships:
is_not_in_only = only_fields and relationship.key not in only_fields
is_already_created = relationship.key in options.fields
is_excluded = relationship.key in exclude_fields or is_already_created
if is_not_in_only or is_excluded:
# We skip this field if we specify only_fields and is not
# in there. Or when we excldue this field in exclude_fields
continue
converted_relationship = convert_sqlalchemy_relationship(relationship, options.registry)
name = relationship.key
fields[name] = converted_relationship
return fields
class SQLAlchemyObjectTypeMeta(ObjectTypeMeta): class SQLAlchemyObjectTypeMeta(ObjectTypeMeta):
def _construct_fields(cls, all_fields, options):
only_fields = cls._meta.only_fields
exclude_fields = cls._meta.exclude_fields
inspected_model = sqlalchemyinspect(cls._meta.model)
fields = OrderedDict()
for name, column in inspected_model.columns.items():
is_not_in_only = only_fields and name not in only_fields
is_already_created = name in all_fields
is_excluded = name in exclude_fields or is_already_created
if is_not_in_only or is_excluded:
# We skip this field if we specify only_fields and is not
# in there. Or when we excldue this field in exclude_fields
continue
converted_column = convert_sqlalchemy_column(column, options.registry)
fields[name] = converted_column
# Get all the columns for the relationships on the model
for relationship in inspected_model.relationships:
is_not_in_only = only_fields and relationship.key not in only_fields
is_already_created = relationship.key in all_fields
is_excluded = relationship.key in exclude_fields or is_already_created
if is_not_in_only or is_excluded:
# We skip this field if we specify only_fields and is not
# in there. Or when we excldue this field in exclude_fields
continue
converted_relationship = convert_sqlalchemy_relationship(relationship, options.registry)
name = relationship.key
fields[name] = converted_relationship
return fields
@staticmethod @staticmethod
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
@ -89,9 +91,14 @@ class SQLAlchemyObjectTypeMeta(ObjectTypeMeta):
options.sqlalchemy_fields = get_fields_in_type( options.sqlalchemy_fields = get_fields_in_type(
ObjectType, ObjectType,
cls._construct_fields(options.fields, options) construct_fields(options)
)
options.fields = merge(
options.interface_fields,
options.sqlalchemy_fields,
options.base_fields,
options.local_fields
) )
options.fields.update(options.sqlalchemy_fields)
return cls return cls