Skip to content

Commit 14f9c1a

Browse files
authored
Release 0.1.3 (#4)
1 parent 7863fc5 commit 14f9c1a

File tree

8 files changed

+99
-29
lines changed

8 files changed

+99
-29
lines changed

CHANGES.rst

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
0.1.3
2+
=====
3+
4+
* Initial functional release

docs/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
author = 'Maxim Avanov'
2323

2424
# The full version, including alpha/beta/rc tags
25-
release = '0.1.2'
25+
release = '0.1.3'
2626

2727

2828
# -- General configuration ---------------------------------------------------

docs/index.rst

+65-5
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
graphql-dsl
88
===========
99

10-
Compose GraphQL queries by defining Python types
11-
------------------------------------------------
10+
.. contents::
11+
:local:
12+
13+
Quick intro
14+
===========
1215

1316
Let's take a manually written `GraphQL query <https://graphql.org/learn/schema/#the-query-and-mutation-types>`_:
1417

@@ -85,9 +88,66 @@ field reference syntax (because dataclasses don't define class-level field gette
8588
| PASS | (Input, 'droid_id') * TO * (HeroAndDroid, 'droid') * AS * 'id'
8689
)
8790
88-
Indices and tables
89-
==================
91+
Simple queries
92+
--------------
93+
94+
Let's use `Countries API <https://countries.trevorblades.com/>`_ and prepare the simplest query for it.
95+
96+
We want to fetch a list of all country codes
97+
98+
.. code-block:: python
99+
100+
from typing import Sequence, NamedTuple
101+
102+
class Country(NamedTuple):
103+
code: str
104+
105+
class Query(NamedTuple):
106+
countries: Sequence[Country]
107+
108+
We can start composing our query with:
109+
110+
.. code-block:: python
111+
112+
from graphql_dsl import QUERY
113+
114+
countries_query = QUERY | Query
115+
116+
117+
If we don't need to provide input parameters to the query, we can immediately compile it:
118+
119+
.. code-block:: python
120+
121+
from graphql_dsl import GQL
122+
123+
compiled_query = GQL(countries_query)
124+
125+
126+
Now we are able to call the service and receive the typed result from it:
127+
128+
.. code-block:: python
129+
130+
import requests
131+
132+
response = requests.post(
133+
url="https://countries.trevorblades.com/",
134+
json={
135+
"operationName": compiled_query.name,
136+
"query": compiled_query.query,
137+
}
138+
)
139+
140+
data = compiled_query.get_result(response)
141+
assert isinstance(data, Query)
142+
143+
# will print AD, AE, AF, AG, AI, AL, AM, AO, ...
144+
print(', '.join(country.code for country in data.countries))
145+
146+
147+
148+
Documentation Indices and tables
149+
================================
90150

91151
* :ref:`genindex`
92152
* :ref:`modindex`
93-
* :ref:`search`
153+
* :ref:`search`

graphql_dsl/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
'QUERY',
77
'WITH',
88
'PASS',
9-
'MUTATION',
9+
'MUTATE',
1010
'TO',
1111
'AS',
1212
'GQL',

graphql_dsl/dsl.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
'PASS',
2323
'TO',
2424
'AS',
25-
'MUTATION',
25+
'MUTATE',
2626
'GQL',
2727
)
2828

@@ -95,7 +95,9 @@ class ResolvedBinding(NamedTuple):
9595

9696
class GraphQLQuery(NamedTuple):
9797
query: str
98+
name: str
9899
get_input_vars: Callable[..., Mapping[str, Any]]
100+
get_result: Callable[[Mapping[str, Any]], Any]
99101

100102

101103
class GraphQLQueryConstructor(NamedTuple):
@@ -104,12 +106,15 @@ class GraphQLQueryConstructor(NamedTuple):
104106

105107
def __call__(self, expr: 'Expr') -> GraphQLQuery:
106108
mk_input_vars, dict_input_vars = self.typer ^ expr.input
109+
mk_result, dict_result = self.typer ^ expr.query
107110
bindings = self.prepare_bindings(expr)
108111
query_decl = expr.type.value
109112
query_body = translate(expr.query, bindings, self.typer)
110113
return GraphQLQuery(
114+
name=expr.query.__name__,
111115
query=f'{query_decl} {query_body}',
112116
get_input_vars=dict_input_vars,
117+
get_result=lambda x: mk_result(x['data']),
113118
)
114119

115120
def prepare_bindings(self, expr: Expr) -> Mapping[str, Iterable[ResolvedBinding]]:
@@ -162,8 +167,8 @@ def __or__(self, other: Union[Type[Any], Expr]) -> Expr:
162167
return Expr(type=self.type, query=other)
163168

164169

165-
QUERY = Query(QueryType.QUERY)
166-
MUTATION = Query(QueryType.MUTATION)
170+
QUERY = Query(QueryType.QUERY)
171+
MUTATE = Query(QueryType.MUTATION)
167172

168173

169174
@infix

setup.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# ----------------------------
2222

2323
setup(name='graphql-dsl',
24-
version='0.1.2',
24+
version='0.1.3',
2525
description='GraphQL DSL',
2626
long_description=README,
2727
classifiers=[
@@ -33,10 +33,17 @@
3333
'Programming Language :: Python :: 3',
3434
'Operating System :: POSIX',
3535
'Topic :: Internet :: WWW/HTTP',
36+
'Topic :: Software Development :: Libraries',
37+
'Topic :: Software Development :: Code Generators',
38+
'Typing :: Typed',
3639
],
3740
author='Maxim Avanov',
3841
author_email='[email protected]',
3942
url='https://maximavanov.com/',
43+
project_urls={
44+
'Documentation': 'https://graphql-dsl.rtfd.io/',
45+
'Source': 'https://github.com/avanov/graphql-dsl',
46+
},
4047
keywords='web',
4148
packages=find_packages(exclude=['tests', 'tests.*']),
4249
include_package_data=True,

tests/test_tokenizer.py

+8-12
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ class Country(NamedTuple):
2323
class CountriesQuery(NamedTuple):
2424
countries: Sequence[Country]
2525

26-
27-
mk_countries_query, dict_countries_query = GQL.typer ^ CountriesQuery
28-
2926
q = QUERY | CountriesQuery
3027

3128
graphql_query = GQL(q)
@@ -36,20 +33,19 @@ class CountriesQuery(NamedTuple):
3633
response = requests.post(
3734
url='https://countries.trevorblades.com/',
3835
json={
39-
"operationName": f"{CountriesQuery.__name__}",
36+
"operationName": graphql_query.name,
4037
"variables": {},
4138
"query": graphql_query.query,
4239
},
4340
headers={
4441
'Content-Type': 'application/json',
4542
'Accept': 'application/json',
46-
'Origin': 'https://countries.trevorblades.com',
4743
}
4844
)
4945
response.raise_for_status()
50-
data = response.json()['data']
46+
data = response.json()
5147
assert data
52-
typed_data = mk_countries_query(data)
48+
typed_data = graphql_query.get_result(data)
5349
assert isinstance(typed_data, CountriesQuery)
5450

5551

@@ -161,10 +157,10 @@ class Input3(NamedTuple):
161157
class CreateReviewForEpisode(NamedTuple):
162158
create_review: Review
163159

164-
q = GQL(MUTATION | CreateReviewForEpisode
165-
| WITH | Input3
166-
| PASS | Input3.episode * TO * CreateReviewForEpisode.create_review
167-
& Input3.review * TO * CreateReviewForEpisode.create_review
168-
)
160+
q = GQL( MUTATE | CreateReviewForEpisode
161+
| WITH | Input3
162+
| PASS | Input3.episode * TO * CreateReviewForEpisode.create_review
163+
& Input3.review * TO * CreateReviewForEpisode.create_review )
164+
169165
expected = 'mutation CreateReviewForEpisode($episode:Episode!,$review:Review!){createReview(episode:$episode,review:$review){stars commentary}}'
170166
assert q.query == expected

tests/vcr/countries.yaml

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
interactions:
22
- request:
3-
body: '{"operationName": "CountriesQuery", "variables": {}, "query": "query CountriesQuery
4-
{countries{code name languages{code name } } }"}'
3+
body: '{"operationName": "CountriesQuery", "variables": {}, "query": "query CountriesQuery{countries{code
4+
name languages{code name}}}"}'
55
headers:
66
Accept:
77
- application/json
@@ -10,11 +10,9 @@ interactions:
1010
Connection:
1111
- keep-alive
1212
Content-Length:
13-
- '132'
13+
- '128'
1414
Content-Type:
1515
- application/json
16-
Origin:
17-
- https://countries.trevorblades.com
1816
User-Agent:
1917
- python-requests/2.23.0
2018
method: POST
@@ -412,7 +410,7 @@ interactions:
412410
Content-Type:
413411
- application/json; charset=utf-8
414412
Date:
415-
- Sat, 23 May 2020 22:42:28 GMT
413+
- Mon, 25 May 2020 21:15:56 GMT
416414
Etag:
417415
- W/"5b6b-d1+62eE1I7PMiWAV7I5FC0xGL7c"
418416
Server:

0 commit comments

Comments
 (0)