Skip to content

Support manually mapped (e.g. reflected) tables #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion graphene_sqlalchemy/tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from sqlalchemy import Column, Date, ForeignKey, Integer, String, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm import mapper, relationship

Base = declarative_base()

Expand Down Expand Up @@ -41,3 +41,11 @@ class Article(Base):
headline = Column(String(100))
pub_date = Column(Date())
reporter_id = Column(Integer(), ForeignKey('reporters.id'))


class ReflectedEditor:
"""Same as Editor, but using reflected table."""

editor_table = Table('editors', Base.metadata, autoload=True)

mapper(ReflectedEditor, editor_table)
24 changes: 24 additions & 0 deletions graphene_sqlalchemy/tests/test_reflected.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

from graphene import ObjectType

from ..registry import Registry
from ..types import SQLAlchemyObjectType
from .models import ReflectedEditor

registry = Registry()


class Reflected(SQLAlchemyObjectType):

class Meta:
model = ReflectedEditor
registry = registry


def test_objecttype_registered():
assert issubclass(Reflected, ObjectType)
assert Reflected._meta.model == ReflectedEditor
assert list(
Reflected._meta.fields.keys()) == ['editor_id', 'name']


6 changes: 3 additions & 3 deletions graphene_sqlalchemy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
convert_sqlalchemy_composite,
convert_sqlalchemy_relationship)
from .registry import Registry, get_global_registry
from .utils import get_query, is_mapped
from .utils import get_query, is_mapped_class, is_mapped_instance


def construct_fields(options):
Expand Down Expand Up @@ -91,7 +91,7 @@ def __new__(cls, name, bases, attrs):
'The attribute registry in {}.Meta needs to be an'
' instance of Registry, received "{}".'
).format(name, options.registry)
assert is_mapped(options.model), (
assert is_mapped_class(options.model), (
'You need to pass a valid SQLAlchemy Model in '
'{}.Meta, received "{}".'
).format(name, options.model)
Expand Down Expand Up @@ -120,7 +120,7 @@ class SQLAlchemyObjectType(six.with_metaclass(SQLAlchemyObjectTypeMeta, ObjectTy
def is_type_of(cls, root, context, info):
if isinstance(root, cls):
return True
if not is_mapped(type(root)):
if not is_mapped_instance(root):
raise Exception((
'Received incompatible instance "{}".'
).format(root))
Expand Down
22 changes: 19 additions & 3 deletions graphene_sqlalchemy/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from sqlalchemy.ext.declarative.api import DeclarativeMeta
from sqlalchemy.exc import ArgumentError
from sqlalchemy.orm import class_mapper, object_mapper
from sqlalchemy.orm.exc import UnmappedClassError, UnmappedInstanceError


def get_session(context):
Expand All @@ -16,5 +18,19 @@ def get_query(model, context):
return query


def is_mapped(obj):
return isinstance(obj, DeclarativeMeta)
def is_mapped_class(cls):
try:
class_mapper(cls)
except (ArgumentError, UnmappedClassError):
return False
else:
return True


def is_mapped_instance(cls):
try:
object_mapper(cls)
except (ArgumentError, UnmappedInstanceError):
return False
else:
return True