Skip to content

Commit

Permalink
Rename ResponseParser to TypeAdaptor
Browse files Browse the repository at this point in the history
The 'ResponseParser' name was confusing because it was too broad, and we
weren't really actually parsing the response. Hopefully this makes it
clearer that what we are actually doing it just adding support for custom
types.
  • Loading branch information
Awais Hussain committed May 1, 2018
1 parent 9d80656 commit a13d166
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 32 deletions.
8 changes: 4 additions & 4 deletions gql/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from graphql.validation import validate

from .transport.local_schema import LocalSchemaTransport
from .response_parser import ResponseParser
from .type_adaptor import TypeAdaptor

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -37,7 +37,7 @@ def __init__(self, schema=None, introspection=None, type_def=None, transport=Non
self.introspection = introspection
self.transport = transport
self.retries = retries
self.response_parser = ResponseParser(schema, custom_scalars) if custom_scalars else None
self.type_adaptor = TypeAdaptor(schema, custom_scalars) if custom_scalars else None

def validate(self, document):
if not self.schema:
Expand All @@ -54,8 +54,8 @@ def execute(self, document, *args, **kwargs):
if result.errors:
raise Exception(str(result.errors[0]))

if self.response_parser:
result.data = self.response_parser.parse(result.data)
if self.type_adaptor:
result.data = self.type_adaptor.apply(result.data)

return result.data

Expand Down
24 changes: 14 additions & 10 deletions gql/response_parser.py → gql/type_adaptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@
from graphql.type.definition import GraphQLObjectType, GraphQLField, GraphQLScalarType


class ResponseParser(object):
"""The challenge is to substitute custom scalars in a GQL response with their
decoded counterparts.
class TypeAdaptor(object):
"""Substitute custom scalars in a GQL response with their decoded counterparts.
To solve this problem, we first need to iterate over all the fields in the
response (which is done in the `_traverse()` function).
GQL custom scalar types are defined on the GQL schema and are used to represent
fields which have special behaviour. To define custom scalar type, you need
the type name, and a class which has a class method called `parse_value()` -
this is the function which will be used to deserialize the custom scalar field.
Each time we find a field which has type scalar and is a custom scalar, we
need to replace the value of that field with the decoded value. All of this
logic happens in `_substitute()`.
We first need iterate over all the fields in the response (which is done in
the `_traverse()` function).
Each time we find a field which is a custom scalar (it's type name appears
as a key in self.custom_scalars), we replace the value of that field with the
decoded value. All of this logic happens in `_substitute()`.
Public Interface:
parse(): call parse with a GQL response to replace all instances of custom
parse(): pass in a GQL response to replace all instances of custom
scalar strings with their deserialized representation."""

def __init__(self, schema: GraphQLSchema, custom_scalars: Dict[str, Any] = {}) -> None:
Expand Down Expand Up @@ -110,5 +114,5 @@ def iterate(node: Any, keys: List[str] = []):
return substitute(keys, node)
return iterate(response)

def parse(self, response: Dict[str, Any]) -> Dict[str, Any]:
def apply(self, response: Dict[str, Any]) -> Dict[str, Any]:
return self._traverse(response, self._substitute)
36 changes: 18 additions & 18 deletions tests/test_response_parser.py → tests/test_type_adaptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
locally.
"""
import copy
from gql.response_parser import ResponseParser
from gql.type_adaptor import TypeAdaptor
import pytest
import requests
from gql import Client
Expand Down Expand Up @@ -36,37 +36,37 @@ def schema():
return client.schema

def test_scalar_type_name_for_scalar_field_returns_name(schema):
parser = ResponseParser(schema)
type_adaptor = TypeAdaptor(schema)
schema_obj = schema.get_query_type().fields['film']

assert parser._get_scalar_type_name(schema_obj.type.fields['releaseDate']) == 'DateTime'
assert type_adaptor ._get_scalar_type_name(schema_obj.type.fields['releaseDate']) == 'DateTime'


def test_scalar_type_name_for_non_scalar_field_returns_none(schema):
parser = ResponseParser(schema)
type_adaptor = TypeAdaptor(schema)
schema_obj = schema.get_query_type().fields['film']

assert parser._get_scalar_type_name(schema_obj.type.fields['species']) is None
assert type_adaptor._get_scalar_type_name(schema_obj.type.fields['species']) is None

def test_lookup_scalar_type(gql_schema):
parser = ResponseParser(gql_schema)
def test_lookup_scalar_type(schema):
type_adaptor = TypeAdaptor(schema)

assert parser._lookup_scalar_type(["film"]) is None
assert parser._lookup_scalar_type(["film", "releaseDate"]) == 'DateTime'
assert parser._lookup_scalar_type(["film", "species"]) is None
assert type_adaptor._lookup_scalar_type(["film"]) is None
assert type_adaptor._lookup_scalar_type(["film", "releaseDate"]) == 'DateTime'
assert type_adaptor._lookup_scalar_type(["film", "species"]) is None

def test_lookup_scalar_type_in_mutation(schema):
parser = ResponseParser(schema)
type_adaptor = TypeAdaptor(schema)

assert parser._lookup_scalar_type(["createHero"]) is None
assert parser._lookup_scalar_type(["createHero", "hero"]) is None
assert parser._lookup_scalar_type(["createHero", "ok"]) == 'Boolean'
assert type_adaptor._lookup_scalar_type(["createHero"]) is None
assert type_adaptor._lookup_scalar_type(["createHero", "hero"]) is None
assert type_adaptor._lookup_scalar_type(["createHero", "ok"]) == 'Boolean'

def test_parse_response(schema):
custom_scalars = {
'DateTime': Capitalize
}
parser = ResponseParser(schema, custom_scalars)
type_adaptor = TypeAdaptor(schema, custom_scalars)

response = {
'film': {
Expand All @@ -82,14 +82,14 @@ def test_parse_response(schema):
}
}

assert parser.parse(response) == expected
assert type_adaptor.apply(response) == expected
assert response['film']['releaseDate'] == 'some_datetime' # ensure original response is not changed

def test_parse_response_containing_list(schema):
custom_scalars = {
'DateTime': Capitalize
}
parser = ResponseParser(schema, custom_scalars)
type_adaptor = TypeAdaptor(schema, custom_scalars)

response = {
"allFilms": {
Expand All @@ -111,7 +111,7 @@ def test_parse_response_containing_list(schema):
expected['allFilms']['edges'][0]['node']['releaseDate'] = "SOME_DATETIME"
expected['allFilms']['edges'][1]['node']['releaseDate'] = "SOME_OTHER_DATETIME"

result = parser.parse(response)
result = type_adaptor.apply(response)

assert result == expected
expected['allFilms']['edges'][0]['node']['releaseDate'] = "some_datetime"
Expand Down

0 comments on commit a13d166

Please sign in to comment.