Merge pull request #146 from karec/master

Add meta attribute identifier for SQLAlchemyNode
This commit is contained in:
Syrus Akbary 2016-04-13 13:16:15 -07:00
commit 4d0d542d35
8 changed files with 105 additions and 10 deletions

View File

@ -12,9 +12,14 @@ default_query = '''
allEmployees {
edges {
node {
id
name
id,
name,
department {
id,
name
},
role {
id,
name
}
}

View File

@ -14,7 +14,7 @@ def init_db():
# import all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
from models import Department, Employee
from models import Department, Employee, Role
Base.metadata.drop_all(bind=engine)
Base.metadata.create_all(bind=engine)
@ -24,10 +24,15 @@ def init_db():
hr = Department(name='Human Resources')
db_session.add(hr)
peter = Employee(name='Peter', department=engineering)
manager = Role(name='manager')
db_session.add(manager)
engineer = Role(name='engineer')
db_session.add(engineer)
peter = Employee(name='Peter', department=engineering, role=engineer)
db_session.add(peter)
roy = Employee(name='Roy', department=engineering)
roy = Employee(name='Roy', department=engineering, role=engineer)
db_session.add(roy)
tracy = Employee(name='Tracy', department=hr)
tracy = Employee(name='Tracy', department=hr, role=manager)
db_session.add(tracy)
db_session.commit()

View File

@ -10,6 +10,12 @@ class Department(Base):
name = Column(String)
class Role(Base):
__tablename__ = 'roles'
role_id = Column(Integer, primary_key=True)
name = Column(String)
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
@ -19,9 +25,15 @@ class Employee(Base):
# Employee record was created
hired_on = Column(DateTime, default=func.now())
department_id = Column(Integer, ForeignKey('department.id'))
role_id = Column(Integer, ForeignKey('roles.role_id'))
# Use cascade='delete,all' to propagate the deletion of a Department onto its Employees
department = relationship(
Department,
backref=backref('employees',
uselist=True,
cascade='delete,all'))
role = relationship(
Role,
backref=backref('roles',
uselist=True,
cascade='delete,all'))

View File

@ -4,6 +4,7 @@ from graphene.contrib.sqlalchemy import (SQLAlchemyConnectionField,
SQLAlchemyNode)
from models import Department as DepartmentModel
from models import Employee as EmployeeModel
from models import Role as RoleModel
schema = graphene.Schema()
@ -22,8 +23,18 @@ class Employee(SQLAlchemyNode):
model = EmployeeModel
@schema.register
class Role(SQLAlchemyNode):
class Meta:
model = RoleModel
identifier = 'role_id'
class Query(graphene.ObjectType):
node = relay.NodeField()
node = relay.NodeField(Employee)
all_employees = SQLAlchemyConnectionField(Employee)
all_roles = SQLAlchemyConnectionField(Role)
role = relay.NodeField(Role)
schema.query = Query

View File

@ -2,7 +2,7 @@ from ...core.classtypes.objecttype import ObjectTypeOptions
from ...relay.types import Node
from ...relay.utils import is_node
VALID_ATTRS = ('model', 'only_fields', 'exclude_fields')
VALID_ATTRS = ('model', 'only_fields', 'exclude_fields', 'identifier')
class SQLAlchemyOptions(ObjectTypeOptions):
@ -10,6 +10,7 @@ class SQLAlchemyOptions(ObjectTypeOptions):
def __init__(self, *args, **kwargs):
super(SQLAlchemyOptions, self).__init__(*args, **kwargs)
self.model = None
self.identifier = "id"
self.valid_attrs += VALID_ATTRS
self.only_fields = None
self.exclude_fields = []

View File

@ -11,6 +11,12 @@ association_table = Table('association', Base.metadata,
Column('reporter_id', Integer, ForeignKey('reporters.id')))
class Editor(Base):
__tablename__ = 'editors'
editor_id = Column(Integer(), primary_key=True)
name = Column(String(100))
class Pet(Base):
__tablename__ = 'pets'
id = Column(Integer(), primary_key=True)

View File

@ -7,7 +7,7 @@ from graphene import relay
from graphene.contrib.sqlalchemy import (SQLAlchemyConnectionField,
SQLAlchemyNode, SQLAlchemyObjectType)
from .models import Article, Base, Reporter
from .models import Article, Base, Reporter, Editor
db = create_engine('sqlite:///test_sqlalchemy.sqlite3')
@ -37,6 +37,8 @@ def setup_fixtures(session):
session.add(reporter2)
article = Article(headline='Hi!')
session.add(article)
editor = Editor(name="John")
session.add(editor)
session.commit()
@ -187,3 +189,51 @@ def test_should_node(session):
result = schema.execute(query)
assert not result.errors
assert result.data == expected
def test_should_custom_identifier(session):
setup_fixtures(session)
class EditorNode(SQLAlchemyNode):
class Meta:
model = Editor
identifier = "editor_id"
class Query(graphene.ObjectType):
node = relay.NodeField(EditorNode)
all_editors = SQLAlchemyConnectionField(EditorNode)
query = '''
query EditorQuery {
allEditors {
edges {
node {
id,
name
}
}
},
node(id: "RWRpdG9yTm9kZTox") {
name
}
}
'''
expected = {
'allEditors': {
'edges': [{
'node': {
'id': 'RWRpdG9yTm9kZTox',
'name': 'John'
}
}]
},
'node': {
'name': 'John'
}
}
schema = graphene.Schema(query=Query, session=session)
result = schema.execute(query)
assert not result.errors
assert result.data == expected

View File

@ -109,12 +109,17 @@ class SQLAlchemyNode(six.with_metaclass(
class Meta:
abstract = True
def to_global_id(self):
id_ = getattr(self.instance, self._meta.identifier)
return self.global_id(id_)
@classmethod
def get_node(cls, id, info=None):
try:
model = cls._meta.model
identifier = cls._meta.identifier
query = get_query(model, info)
instance = query.filter(model.id == id).one()
instance = query.filter(getattr(model, identifier) == id).one()
return cls(instance)
except NoResultFound:
return None