Skip to content

Commit 4d0d542

Browse files
committed
Merge pull request #146 from karec/master
Add meta attribute identifier for SQLAlchemyNode
2 parents 8497e0c + 492ffda commit 4d0d542

File tree

8 files changed

+105
-10
lines changed

8 files changed

+105
-10
lines changed

examples/flask_sqlalchemy/app.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@
1212
allEmployees {
1313
edges {
1414
node {
15-
id
16-
name
15+
id,
16+
name,
1717
department {
18+
id,
19+
name
20+
},
21+
role {
22+
id,
1823
name
1924
}
2025
}

examples/flask_sqlalchemy/database.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def init_db():
1414
# import all modules here that might define models so that
1515
# they will be registered properly on the metadata. Otherwise
1616
# you will have to import them first before calling init_db()
17-
from models import Department, Employee
17+
from models import Department, Employee, Role
1818
Base.metadata.drop_all(bind=engine)
1919
Base.metadata.create_all(bind=engine)
2020

@@ -24,10 +24,15 @@ def init_db():
2424
hr = Department(name='Human Resources')
2525
db_session.add(hr)
2626

27-
peter = Employee(name='Peter', department=engineering)
27+
manager = Role(name='manager')
28+
db_session.add(manager)
29+
engineer = Role(name='engineer')
30+
db_session.add(engineer)
31+
32+
peter = Employee(name='Peter', department=engineering, role=engineer)
2833
db_session.add(peter)
29-
roy = Employee(name='Roy', department=engineering)
34+
roy = Employee(name='Roy', department=engineering, role=engineer)
3035
db_session.add(roy)
31-
tracy = Employee(name='Tracy', department=hr)
36+
tracy = Employee(name='Tracy', department=hr, role=manager)
3237
db_session.add(tracy)
3338
db_session.commit()

examples/flask_sqlalchemy/models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ class Department(Base):
1010
name = Column(String)
1111

1212

13+
class Role(Base):
14+
__tablename__ = 'roles'
15+
role_id = Column(Integer, primary_key=True)
16+
name = Column(String)
17+
18+
1319
class Employee(Base):
1420
__tablename__ = 'employee'
1521
id = Column(Integer, primary_key=True)
@@ -19,9 +25,15 @@ class Employee(Base):
1925
# Employee record was created
2026
hired_on = Column(DateTime, default=func.now())
2127
department_id = Column(Integer, ForeignKey('department.id'))
28+
role_id = Column(Integer, ForeignKey('roles.role_id'))
2229
# Use cascade='delete,all' to propagate the deletion of a Department onto its Employees
2330
department = relationship(
2431
Department,
2532
backref=backref('employees',
2633
uselist=True,
2734
cascade='delete,all'))
35+
role = relationship(
36+
Role,
37+
backref=backref('roles',
38+
uselist=True,
39+
cascade='delete,all'))

examples/flask_sqlalchemy/schema.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
SQLAlchemyNode)
55
from models import Department as DepartmentModel
66
from models import Employee as EmployeeModel
7+
from models import Role as RoleModel
78

89
schema = graphene.Schema()
910

@@ -22,8 +23,18 @@ class Meta:
2223
model = EmployeeModel
2324

2425

26+
@schema.register
27+
class Role(SQLAlchemyNode):
28+
29+
class Meta:
30+
model = RoleModel
31+
identifier = 'role_id'
32+
33+
2534
class Query(graphene.ObjectType):
26-
node = relay.NodeField()
35+
node = relay.NodeField(Employee)
2736
all_employees = SQLAlchemyConnectionField(Employee)
37+
all_roles = SQLAlchemyConnectionField(Role)
38+
role = relay.NodeField(Role)
2839

2940
schema.query = Query

graphene/contrib/sqlalchemy/options.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
from ...relay.types import Node
33
from ...relay.utils import is_node
44

5-
VALID_ATTRS = ('model', 'only_fields', 'exclude_fields')
5+
VALID_ATTRS = ('model', 'only_fields', 'exclude_fields', 'identifier')
66

77

88
class SQLAlchemyOptions(ObjectTypeOptions):
99

1010
def __init__(self, *args, **kwargs):
1111
super(SQLAlchemyOptions, self).__init__(*args, **kwargs)
1212
self.model = None
13+
self.identifier = "id"
1314
self.valid_attrs += VALID_ATTRS
1415
self.only_fields = None
1516
self.exclude_fields = []

graphene/contrib/sqlalchemy/tests/models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
Column('reporter_id', Integer, ForeignKey('reporters.id')))
1212

1313

14+
class Editor(Base):
15+
__tablename__ = 'editors'
16+
editor_id = Column(Integer(), primary_key=True)
17+
name = Column(String(100))
18+
19+
1420
class Pet(Base):
1521
__tablename__ = 'pets'
1622
id = Column(Integer(), primary_key=True)

graphene/contrib/sqlalchemy/tests/test_query.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from graphene.contrib.sqlalchemy import (SQLAlchemyConnectionField,
88
SQLAlchemyNode, SQLAlchemyObjectType)
99

10-
from .models import Article, Base, Reporter
10+
from .models import Article, Base, Reporter, Editor
1111

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

@@ -37,6 +37,8 @@ def setup_fixtures(session):
3737
session.add(reporter2)
3838
article = Article(headline='Hi!')
3939
session.add(article)
40+
editor = Editor(name="John")
41+
session.add(editor)
4042
session.commit()
4143

4244

@@ -187,3 +189,51 @@ def resolve_article(self, *args, **kwargs):
187189
result = schema.execute(query)
188190
assert not result.errors
189191
assert result.data == expected
192+
193+
194+
def test_should_custom_identifier(session):
195+
setup_fixtures(session)
196+
197+
class EditorNode(SQLAlchemyNode):
198+
199+
class Meta:
200+
model = Editor
201+
identifier = "editor_id"
202+
203+
class Query(graphene.ObjectType):
204+
node = relay.NodeField(EditorNode)
205+
all_editors = SQLAlchemyConnectionField(EditorNode)
206+
207+
query = '''
208+
query EditorQuery {
209+
allEditors {
210+
edges {
211+
node {
212+
id,
213+
name
214+
}
215+
}
216+
},
217+
node(id: "RWRpdG9yTm9kZTox") {
218+
name
219+
}
220+
}
221+
'''
222+
expected = {
223+
'allEditors': {
224+
'edges': [{
225+
'node': {
226+
'id': 'RWRpdG9yTm9kZTox',
227+
'name': 'John'
228+
}
229+
}]
230+
},
231+
'node': {
232+
'name': 'John'
233+
}
234+
}
235+
236+
schema = graphene.Schema(query=Query, session=session)
237+
result = schema.execute(query)
238+
assert not result.errors
239+
assert result.data == expected

graphene/contrib/sqlalchemy/types.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,17 @@ class SQLAlchemyNode(six.with_metaclass(
109109
class Meta:
110110
abstract = True
111111

112+
def to_global_id(self):
113+
id_ = getattr(self.instance, self._meta.identifier)
114+
return self.global_id(id_)
115+
112116
@classmethod
113117
def get_node(cls, id, info=None):
114118
try:
115119
model = cls._meta.model
120+
identifier = cls._meta.identifier
116121
query = get_query(model, info)
117-
instance = query.filter(model.id == id).one()
122+
instance = query.filter(getattr(model, identifier) == id).one()
118123
return cls(instance)
119124
except NoResultFound:
120125
return None

0 commit comments

Comments
 (0)