Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bidirectional scalars #24

Merged
merged 13 commits into from
Sep 12, 2018
20 changes: 14 additions & 6 deletions ariadne/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,24 @@ def add_resolve_functions_to_schema(schema: GraphQLSchema, resolvers: dict):
if isinstance(type_object, GraphQLObjectType):
add_resolve_functions_to_object(type_name, type_object, resolvers)
if isinstance(type_object, GraphQLScalarType):
add_resolve_function_to_scalar(type_name, type_object, resolvers)
add_resolve_functions_to_scalar(type_name, type_object, resolvers)


def add_resolve_functions_to_object(name: str, obj: GraphQLObjectType, resolvers: dict):
type_resolver = resolvers.get(name, {})
type_resolvers = resolvers.get(name, {})
for field_name, field_object in obj.fields.items():
field_resolver = type_resolver.get(field_name, default_resolver)
field_resolver = type_resolvers.get(field_name, default_resolver)
field_object.resolver = field_resolver


def add_resolve_function_to_scalar(name: str, obj: GraphQLObjectType, resolvers: dict):
serializer = resolvers.get(name, obj.serialize)
obj.serialize = serializer
def add_resolve_functions_to_scalar(name: str, obj: GraphQLObjectType, resolvers: dict):
scalar_resolvers = resolvers.get(name, {})

serialize = scalar_resolvers.get("serialize", obj.serialize)
obj.serialize = serialize

parse_literal = scalar_resolvers.get("parse_literal", obj.parse_literal)
obj.parse_literal = parse_literal

parse_value = scalar_resolvers.get("parse_value", obj.parse_value)
obj.parse_value = parse_value
128 changes: 128 additions & 0 deletions tests/test_custom_scalars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
from datetime import date, datetime

from graphql import graphql
from graphql.language.ast import StringValue

from ariadne import make_executable_schema

TEST_DATE = date(2006, 9, 13)
TEST_DATE_SERIALIZED = TEST_DATE.strftime("%Y-%m-%d")

type_defs = """
scalar DateReadOnly
scalar DateInput

type Query {
testSerialize: DateReadOnly!
testInput(value: DateInput!): Boolean!
}
"""


def serialize(date):
return date.strftime("%Y-%m-%d")


def parse_literal(ast):
if not isinstance(ast, StringValue):
return None

formatted_date = ast.value
try:
parsed_datetime = datetime.strptime(formatted_date, "%Y-%m-%d")
return parsed_datetime.date()
except ValueError:
pass


def parse_value(formatted_date):
try:
parsed_datetime = datetime.strptime(formatted_date, "%Y-%m-%d")
return parsed_datetime.date()
except (TypeError, ValueError):
return None


def resolve_test_serialize(*_):
return TEST_DATE


def resolve_test_input(*_, value):
assert value == TEST_DATE
return True


resolvers = {
"Query": {"testSerialize": resolve_test_serialize, "testInput": resolve_test_input},
"DateReadOnly": {"serialize": serialize},
"DateInput": {"parse_literal": parse_literal, "parse_value": parse_value},
}

schema = make_executable_schema(type_defs, resolvers)


def test_serialize_date_obj_to_date_str():
result = graphql(schema, "{ testSerialize }")
assert result.errors is None
assert result.data == {"testSerialize": TEST_DATE_SERIALIZED}


def test_parse_literal_valid_str_ast_to_date_instance():
test_input = TEST_DATE_SERIALIZED
result = graphql(schema, '{ testInput(value: "%s") }' % test_input)
assert result.errors is None
assert result.data == {"testInput": True}


def test_parse_literal_invalid_str_ast_to_date_instance():
salwator marked this conversation as resolved.
Show resolved Hide resolved
test_input = "invalid string"
result = graphql(schema, '{ testInput(value: "%s") }' % test_input)
assert result.errors is not None
assert str(result.errors[0]).splitlines() == [
'Argument "value" has invalid value "invalid string".',
'Expected type "DateInput", found "invalid string".',
]


def test_parse_literal_invalid_int_ast_errors():
test_input = 123
result = graphql(schema, "{ testInput(value: %s) }" % test_input)
assert result.errors is not None
assert str(result.errors[0]).splitlines() == [
'Argument "value" has invalid value 123.',
'Expected type "DateInput", found 123.',
]


parametrized_query = """
query parseValueTest($value: DateInput!) {
testInput(value: $value)
}
"""


def test_parse_value_valid_date_str_returns_date_instance():
variables = {"value": TEST_DATE_SERIALIZED}
result = graphql(schema, parametrized_query, variables=variables)
assert result.errors is None
assert result.data == {"testInput": True}


def test_parse_value_invalid_str_errors():
variables = {"value": "invalid string"}
result = graphql(schema, parametrized_query, variables=variables)
assert result.errors is not None
assert str(result.errors[0]).splitlines() == [
'Variable "$value" got invalid value "invalid string".',
'Expected type "DateInput", found "invalid string".',
]


def test_parse_value_invalid_value_type_int_errors():
variables = {"value": 123}
result = graphql(schema, parametrized_query, variables=variables)
assert result.errors is not None
assert str(result.errors[0]).splitlines() == [
'Variable "$value" got invalid value 123.',
'Expected type "DateInput", found 123.',
]
24 changes: 1 addition & 23 deletions tests/test_queries.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from datetime import date
from unittest.mock import Mock

from graphql import graphql

from ariadne import make_executable_schema, resolve_to


def test_query_default_scalar():
def test_query_root_type_default_resolver():
type_defs = """
type Query {
test: String
Expand All @@ -22,27 +21,6 @@ def test_query_default_scalar():
assert result.data == {"test": "success"}


def test_query_custom_scalar():
type_defs = """
scalar Date

type Query {
test: Date
}
"""

resolvers = {
"Query": {"test": lambda *_: date.today()},
"Date": lambda date: date.strftime("%Y-%m-%d"),
}

schema = make_executable_schema(type_defs, resolvers)

result = graphql(schema, "{ test }")
assert result.errors is None
assert result.data == {"test": date.today().strftime("%Y-%m-%d")}


def test_query_custom_type_default_resolver():
type_defs = """
type Query {
Expand Down