Skip to content

Commit

Permalink
Merge pull request #140 from evo-company/fix-scalars-for-options
Browse files Browse the repository at this point in the history
Fix custom scalar validations for options
  • Loading branch information
kindermax authored Oct 17, 2023
2 parents 888b93d + 26e2f46 commit 1c8bffe
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 71 deletions.
6 changes: 6 additions & 0 deletions hiku/validate/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from contextlib import contextmanager
from collections import abc as collections_abc

from hiku.scalar import ScalarMeta

from ..types import (
AbstractTypeVisitor,
IDMeta,
Expand Down Expand Up @@ -244,6 +246,10 @@ def visit_typeref(self, type_: TypeRefMeta) -> None:
), f'"{type_.__type_name__}" type is not present in graph data_types'
self.visit(self._data_types[type_.__type_name__])

# TODO: add scalar validation errors
def visit_scalar(self, type_: ScalarMeta) -> None:
pass


class _ValidateOptions(GraphVisitor):
"""
Expand Down
252 changes: 181 additions & 71 deletions tests/test_scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from hiku.utils import listify
from hiku.readers.graphql import read
from hiku.validate.graph import GraphValidationError
from hiku.validate.query import validate


def execute(graph, query):
Expand All @@ -22,82 +23,135 @@ def execute(graph, query):
class SomeType:
...


def test_validate_graph_invalid_scalars():
with pytest.raises(GraphValidationError) as err:
Graph([
Node('User', [
Field('id', Integer, lambda: None),
Field('dateCreated', SomeType, lambda: None),
]),
Root([
Link('user', Optional[TypeRef['User']], lambda: None, requires=None),
]),
])
Graph(
[
Node(
"User",
[
Field("id", Integer, lambda: None),
Field("dateCreated", SomeType, lambda: None),
],
),
Root(
[
Link(
"user",
Optional[TypeRef["User"]],
lambda: None,
requires=None,
),
]
),
]
)

assert err.value.errors == [
'Field "User.dateCreated" has type "<class \'tests.test_scalar.SomeType\'>" but Hiku does not support it.',
]


def test_validate_graph_not_defined_scalars():

class SomeType(Scalar):
...

with pytest.raises(GraphValidationError) as err:
Graph([
Node('User', [
Field('id', Integer, lambda: None),
Field('dateCreated', SomeType, lambda: None),
]),
Root([
Link('user', Optional[TypeRef['User']], lambda: None, requires=None),
]),
])
Graph(
[
Node(
"User",
[
Field("id", Integer, lambda: None),
Field("dateCreated", SomeType, lambda: None),
],
),
Root(
[
Link(
"user",
Optional[TypeRef["User"]],
lambda: None,
requires=None,
),
]
),
]
)

assert err.value.errors == [
'Field "User.dateCreated" has type "<class \'tests.test_scalar.test_validate_graph_not_defined_scalars.<locals>.SomeType\'>" but no scalar is defined for it. '
'Maybe you forgot to add new scalar to Graph(..., scalars)?',
"Maybe you forgot to add new scalar to Graph(..., scalars)?",
]


DATE_CREATED = datetime(2023, 6, 15, 12, 30, 59, 0)
DATE_CREATED_STR = '2023-06-15T12:30:59' # TODO: check timezone
DATE_CREATED_STR = "2023-06-15T12:30:59" # TODO: check timezone


def test_serialize_scalar_field_correct():
@listify
def resolve_user_fields(fields, ids):
def get_field(fname, id_):
if fname == 'id':
if fname == "id":
return id_
elif fname == 'dateCreated':
elif fname == "dateCreated":
return DATE_CREATED
elif fname == 'dateCreatedMany':
elif fname == "dateCreatedMany":
return [DATE_CREATED]
elif fname == 'dateCreatedManyOptional':
elif fname == "dateCreatedManyOptional":
return [DATE_CREATED, None]
elif fname == 'dateCreatedMaybe':
elif fname == "dateCreatedMaybe":
return None
elif fname == 'dateCreatedMaybeSequence':
elif fname == "dateCreatedMaybeSequence":
return []

for id_ in ids:
yield [get_field(f.name, id_) for f in fields]

graph = Graph([
Node('User', [
Field('id', Integer, resolve_user_fields),
Field('dateCreated', DateTime, resolve_user_fields),
Field('dateCreatedMany', Sequence[DateTime], resolve_user_fields),
Field('dateCreatedManyOptional', Sequence[Optional[DateTime]], resolve_user_fields),
Field('dateCreatedMaybe', Optional[DateTime], resolve_user_fields),
Field('dateCreatedMaybeSequence', Optional[Sequence[DateTime]], resolve_user_fields),
]),
Root([
Link('user', Optional[TypeRef['User']], lambda: 1, requires=None),
]),
], scalars=[DateTime])
graph = Graph(
[
Node(
"User",
[
Field("id", Integer, resolve_user_fields),
Field("dateCreated", DateTime, resolve_user_fields),
Field(
"dateCreatedMany",
Sequence[DateTime],
resolve_user_fields,
),
Field(
"dateCreatedManyOptional",
Sequence[Optional[DateTime]],
resolve_user_fields,
),
Field(
"dateCreatedMaybe",
Optional[DateTime],
resolve_user_fields,
),
Field(
"dateCreatedMaybeSequence",
Optional[Sequence[DateTime]],
resolve_user_fields,
),
],
),
Root(
[
Link(
"user",
Optional[TypeRef["User"]],
lambda: 1,
requires=None,
),
]
),
],
scalars=[DateTime],
)

query = """
query GetUser {
Expand All @@ -113,13 +167,13 @@ def get_field(fname, id_):
"""
result = execute(graph, read(query))
assert result == {
'user': {
'id': 1,
'dateCreated': DATE_CREATED_STR,
'dateCreatedMany': [DATE_CREATED_STR],
'dateCreatedManyOptional': [DATE_CREATED_STR, None],
'dateCreatedMaybe': None,
'dateCreatedMaybeSequence': [],
"user": {
"id": 1,
"dateCreated": DATE_CREATED_STR,
"dateCreatedMany": [DATE_CREATED_STR],
"dateCreatedManyOptional": [DATE_CREATED_STR, None],
"dateCreatedMaybe": None,
"dateCreatedMaybeSequence": [],
}
}

Expand All @@ -128,39 +182,47 @@ def test_parse_scalar_input_correct():
@listify
def resolve_user_fields(fields, ids):
def get_field(fname, id_):
if fname == 'id':
if fname == "id":
return id_
elif fname == 'dateCreated':
elif fname == "dateCreated":
return DATE_CREATED

for id_ in ids:
yield [get_field(f.name, id_) for f in fields]

def link_user(opts):
if opts['dateCreated'] == DATE_CREATED:
if opts["dateCreated"] == DATE_CREATED:
return 1

return Nothing

graph = Graph([
Node('User', [
Field('id', Integer, resolve_user_fields),
Field('dateCreated', DateTime, resolve_user_fields),
]),
Root([
Link(
'user',
Optional[TypeRef['User']],
link_user,
requires=None,
options=[
Option('dateCreated', DateTime),
Option('dateCreatedMany', Sequence[DateTime]),
Option('dateCreatedMaybe', Optional[DateTime]),
graph = Graph(
[
Node(
"User",
[
Field("id", Integer, resolve_user_fields),
Field("dateCreated", DateTime, resolve_user_fields),
],
),
Root(
[
Link(
"user",
Optional[TypeRef["User"]],
link_user,
requires=None,
options=[
Option("dateCreated", DateTime),
Option("dateCreatedMany", Sequence[DateTime]),
Option("dateCreatedMaybe", Optional[DateTime]),
],
),
]
),
]),
], scalars=[DateTime])
],
scalars=[DateTime],
)

query = """
query GetUser {
Expand All @@ -169,12 +231,60 @@ def link_user(opts):
dateCreated
}
}
""" % (DATE_CREATED_STR, DATE_CREATED_STR)
""" % (
DATE_CREATED_STR,
DATE_CREATED_STR,
)

result = execute(graph, read(query))
assert result == {
'user': {
'id': 1,
'dateCreated': DATE_CREATED_STR,
"user": {
"id": 1,
"dateCreated": DATE_CREATED_STR,
}
}


def test_validate_scalar_input_correct():
graph = Graph(
[
Node(
"User",
[
Field("id", Integer, lambda fields, ids: None),
Field("dateCreated", DateTime, lambda fields, ids: None),
],
),
Root(
[
Link(
"user",
Optional[TypeRef["User"]],
lambda opts: None,
requires=None,
options=[
Option("dateCreated", DateTime),
Option("dateCreatedMany", Sequence[DateTime]),
Option("dateCreatedMaybe", Optional[DateTime]),
],
),
]
),
],
scalars=[DateTime],
)

query = """
query GetUser {
user(dateCreated: "%s", dateCreatedMany: ["%s"], dateCreatedMaybe: null) {
id
dateCreated
}
}
""" % (
DATE_CREATED_STR,
DATE_CREATED_STR,
)

errors = validate(graph, read(query))
assert errors == []

0 comments on commit 1c8bffe

Please sign in to comment.