Skip to content

Commit 6f7e00a

Browse files
committed
Improved query support
1 parent 017f6ae commit 6f7e00a

File tree

5 files changed

+129
-6
lines changed

5 files changed

+129
-6
lines changed

graphene/contrib/sqlalchemy/tests/test_query.py

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import pytest
22

33
import graphene
4-
from graphene.contrib.sqlalchemy import SQLAlchemyObjectType
4+
from graphene import relay
5+
from graphene.contrib.sqlalchemy import SQLAlchemyObjectType, SQLAlchemyNode
56
from sqlalchemy import create_engine
67
from sqlalchemy.orm import scoped_session, sessionmaker
78

8-
from .models import Base, Reporter
9+
from .models import Base, Reporter, Article
910

1011
db = create_engine('sqlite:///test_sqlalchemy.sqlite3')
1112

@@ -33,6 +34,8 @@ def setup_fixtures(session):
3334
session.add(reporter)
3435
reporter2 = Reporter(first_name='ABO', last_name='Y')
3536
session.add(reporter2)
37+
article = Article(headline='Hi!')
38+
session.add(article)
3639
session.commit()
3740

3841

@@ -82,3 +85,89 @@ def resolve_reporters(self, *args, **kwargs):
8285
result = schema.execute(query)
8386
assert not result.errors
8487
assert result.data == expected
88+
89+
90+
def test_should_node(session):
91+
setup_fixtures(session)
92+
93+
class ReporterNode(SQLAlchemyNode):
94+
95+
class Meta:
96+
model = Reporter
97+
98+
@classmethod
99+
def get_node(cls, id, info):
100+
return Reporter(id=2, first_name='Cookie Monster')
101+
102+
def resolve_articles(self, *args, **kwargs):
103+
return [Article(headline='Hi!')]
104+
105+
class ArticleNode(SQLAlchemyNode):
106+
107+
class Meta:
108+
model = Article
109+
110+
# @classmethod
111+
# def get_node(cls, id, info):
112+
# return Article(id=1, headline='Article node')
113+
114+
class Query(graphene.ObjectType):
115+
node = relay.NodeField()
116+
reporter = graphene.Field(ReporterNode)
117+
article = graphene.Field(ArticleNode)
118+
119+
def resolve_reporter(self, *args, **kwargs):
120+
return Reporter(id=1, first_name='ABA', last_name='X')
121+
122+
def resolve_article(self, *args, **kwargs):
123+
return Article(id=1, headline='Article node')
124+
125+
query = '''
126+
query ReporterQuery {
127+
reporter {
128+
id,
129+
firstName,
130+
articles {
131+
edges {
132+
node {
133+
headline
134+
}
135+
}
136+
}
137+
lastName,
138+
email
139+
}
140+
myArticle: node(id:"QXJ0aWNsZU5vZGU6MQ==") {
141+
id
142+
... on ReporterNode {
143+
firstName
144+
}
145+
... on ArticleNode {
146+
headline
147+
}
148+
}
149+
}
150+
'''
151+
expected = {
152+
'reporter': {
153+
'id': 'UmVwb3J0ZXJOb2RlOjE=',
154+
'firstName': 'ABA',
155+
'lastName': 'X',
156+
'email': None,
157+
'articles': {
158+
'edges': [{
159+
'node': {
160+
'headline': 'Hi!'
161+
}
162+
}]
163+
},
164+
},
165+
'myArticle': {
166+
'id': 'QXJ0aWNsZU5vZGU6MQ==',
167+
'headline': 'Hi!'
168+
}
169+
}
170+
schema = graphene.Schema(query=Query, session=session)
171+
result = schema.execute(query)
172+
assert not result.errors
173+
assert result.data == expected
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from graphene import Schema, ObjectType, String
2+
3+
from ..utils import get_session
4+
5+
6+
def test_get_session():
7+
session = 'My SQLAlchemy session'
8+
schema = Schema(session=session)
9+
10+
class Query(ObjectType):
11+
x = String()
12+
13+
def resolve_x(self, args, info):
14+
return get_session(info)
15+
16+
query = '''
17+
query ReporterQuery {
18+
x
19+
}
20+
'''
21+
22+
schema = Schema(query=Query, session=session)
23+
result = schema.execute(query)
24+
assert not result.errors
25+
assert result.data['x'] == session

graphene/contrib/sqlalchemy/types.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
import six
44

55
from sqlalchemy.inspection import inspect as sqlalchemyinspect
6+
from sqlalchemy.orm.exc import NoResultFound
67

78
from ...core.classtypes.objecttype import ObjectType, ObjectTypeMeta
89
from ...relay.types import Connection, Node, NodeMeta
910
from .converter import (convert_sqlalchemy_column,
1011
convert_sqlalchemy_relationship)
1112
from .options import SQLAlchemyOptions
12-
from .utils import is_mapped
13+
from .utils import is_mapped, get_session
1314

1415

1516
class SQLAlchemyObjectTypeMeta(ObjectTypeMeta):
@@ -116,7 +117,9 @@ class Meta:
116117
@classmethod
117118
def get_node(cls, id, info=None):
118119
try:
119-
instance = cls._meta.model.filter(id=id).one()
120+
model = cls._meta.model
121+
session = get_session(info)
122+
instance = session.query(model).filter(model.id == id).one()
120123
return cls(instance)
121-
except cls._meta.model.DoesNotExist:
124+
except NoResultFound:
122125
return None

graphene/contrib/sqlalchemy/utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ def get_type_for_model(schema, model):
1515
return _type
1616

1717

18+
def get_session(info):
19+
schema = info.schema.graphene_schema
20+
return schema.options.get('session')
21+
22+
1823
def is_mapped(obj):
1924
return isinstance(obj, DeclarativeMeta)
2025
# try:

graphene/core/schema.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class Schema(object):
2626
_executor = None
2727

2828
def __init__(self, query=None, mutation=None, subscription=None,
29-
name='Schema', executor=None, plugins=None, auto_camelcase=True):
29+
name='Schema', executor=None, plugins=None, auto_camelcase=True, **options):
3030
self._types_names = {}
3131
self._types = {}
3232
self.mutation = mutation
@@ -38,6 +38,7 @@ def __init__(self, query=None, mutation=None, subscription=None,
3838
if auto_camelcase:
3939
plugins.append(CamelCase())
4040
self.plugins = PluginManager(self, plugins)
41+
self.options = options
4142
signals.init_schema.send(self)
4243

4344
def __repr__(self):

0 commit comments

Comments
 (0)