def test_nested_objects(): Baz = Object("Baz") @Baz.field("val") def resolve_baz_val(root, info) -> str: return "BAZ-VALUE!" Bar = Object("Bar", {"baz": Baz}) @Bar.field("baz") def resolve_bar_baz(root, info) -> Baz: return Baz() Foo = Object("Foo", {"bar": Bar}) @Foo.field("bar") def resolve_foo_bar(root, info) -> Bar: return Bar() Query = Object("Query", {"foo": Foo}) @Query.field("foo") def resolve_query_foo(root, info) -> Foo: return Foo() schema = Schema(query=Query) result = schema.execute("{foo {bar {baz {val}}}}") assert result.errors is None assert result.data == {"foo": {"bar": {"baz": {"val": "BAZ-VALUE!"}}}}
def schema(self): schema = Schema() Success = Object( "Success", { "ok": bool, "result_id": int, }, ) Error = Object( "Error", { "ok": bool, "error_message": str, }, ) Result = pyql.Union("Result", [Success, Error]) @schema.query.field("action") def resolve_action(root, info, id: int) -> Result: if id == 1: return Success(ok=True, result_id=123) if id == 2: return Error(ok=False, error_message="Action failed") return None return schema
def test_input_objects(): Post = Object( "Post", fields={ "id": ID, "title": str, "body": str, }, ) PostInput = InputObject( "PostInput", fields={ "title": NonNull(str), "body": str, }, ) Query = Object("Query", fields={"dummy": str}) Mutation = Object("Mutation") @Mutation.field("create_post") def resolve_create_post(root, info, post: PostInput) -> Post: return Post(id="1", title=post.title, body=post.body) schema = Schema(query=Query, mutation=Mutation) result = schema.execute( """ mutation createPost($post: PostInput!) { createPost(post: $post) { id, title, body } } """, variable_values={"post": { "title": "Hello", "body": "Hello world" }}, ) assert result.errors is None assert result.data == { "createPost": { "id": "1", "title": "Hello", "body": "Hello world", } }
def test_objects_can_reference_each_other(): Foo = Object("Foo", {"name": str}) Bar = Object("Bar", {"name": str}) @Foo.field("bar") def resolve_foo_bar(root, info) -> Bar: return Bar(name="{} bar".format(root.name)) @Bar.field("foo") def resolve_bar_foo(root, info) -> Foo: return Foo(name="{} foo".format(root.name)) schema = Schema() @schema.query.field("foo") def resolve_query_foo(root, info) -> Foo: return Foo(name="FOO") @schema.query.field("bar") def resolve_query_bar(root, info) -> Bar: return Bar(name="BAR") result = schema.execute(""" query { foo { name bar { name foo { name } } } } """) assert result.errors is None assert result.data == { "foo": { "name": "FOO", "bar": { "name": "FOO bar", "foo": { "name": "FOO bar foo" } }, } }
def test_base_scalars_output(): Example = Object( "Example", fields={ "my_str": str, "my_int": int, "my_float": float, "my_bool": bool, "my_id": ID, }, ) schema = Schema() @schema.query.field("example") def resolve_example(root, info) -> Example: return Example( my_str="Some string", my_int=42, my_float=3.14, my_bool=True, my_id="1234" ) result = schema.execute("{ example { myStr, myInt, myFloat, myBool, myId } }") assert result.errors is None assert result.data == { "example": { "myStr": "Some string", "myInt": 42, "myFloat": 3.14, "myBool": True, "myId": "1234", }, }
def test_input_objects_field_names_are_converted(): # See issue #13: https://github.com/rshk/pyql/issues/13 MyInput = InputObject( "MyInput", fields={ "some_field_name": str, }, ) # Need at least one query, for some reason... schema = Schema(query=Object("Query", {"q": str})) @schema.mutation.field("do_something") def resolve_do_something(root, info, obj: MyInput) -> str: return obj.some_field_name result = schema.execute( """ mutation doSomething($obj: MyInput!) { doSomething(obj: $obj) } """, variable_values={"obj": { "someFieldName": "HELLO" }}, ) assert result.errors is None assert result.data == {"doSomething": "HELLO"}
def test_field_names_can_be_camelcase_in_python(): MyInput = InputObject( "MyInput", fields={ "someFieldName": str, }, ) # Need at least one query, for some reason... schema = Schema(query=Object("Query", {"q": str})) @schema.mutation.field("do_something") def resolve_do_something(root, info, obj: MyInput) -> str: with pytest.raises(AttributeError): obj.some_field_name return obj.someFieldName result = schema.execute( """ mutation doSomething($obj: MyInput!) { doSomething(obj: $obj) } """, variable_values={"obj": { "someFieldName": "HELLO" }}, ) assert result.errors is None assert result.data == {"doSomething": "HELLO"}
def test_mutation(): # ...graphql-core forces us to have at least a query Query = Object("Query", fields={"foo": str}) Mutation = Object("Mutation") @Mutation.field("example") def resolve_mutate_something(root, info, text: str) -> bool: return True schema = Schema(query=Query, mutation=Mutation) result = schema.execute( """ mutation foo { example(text: "HEY") } """ ) assert result.errors is None assert result.data == {"example": True}
def test_resolver_cannot_return_different_container_instance(): """ An instance of a different "container" instance is considered a mistake, even if the two are compatible. """ schema = Schema() Foo = Object("Foo", {"text": str}) Bar = Object("Bar", {"text": str}) @schema.query.field("foo") def resolve_foo(root, info) -> Foo: return Bar(text="a") result = schema.execute(""" { foo { text } } """) assert result.data == {"foo": None} assert result.errors is not None assert len(result.errors) == 1 assert (result.errors[0].message == "Expected value of type 'Foo' but got: <Bar instance>.")
def test_mutation_with_variables(): # ...graphql-core forces us to have at least a query Query = Object("Query", fields={"foo": str}) Mutation = Object("Mutation") @Mutation.field("letter_count") def resolve_letter_count(root, info, text: str) -> int: return len(text) schema = Schema(query=Query, mutation=Mutation) result = schema.execute( """ mutation letterCount($text: String!) { result: letterCount(text: $text) } """, variable_values={"text": "HELLO"}, ) assert result.errors is None assert result.data == {"result": 5}
def test_resolver_can_return_dict(): schema = Schema() Foo = Object("Foo", {"text": str}) @schema.query.field("foo") def resolve_foo(root, info) -> Foo: return {"text": "a"} result = schema.execute(""" { foo { text } } """) assert result.errors is None assert result.data == {"foo": {"text": "a"}}
def test_returning_an_incompatible_object_fails(): schema = Schema() Foo = Object("Foo", {"text": str}) Spam = namedtuple("Spam", ("spam", )) @schema.query.field("foo") def resolve_foo(root, info) -> Foo: return Spam(spam="SPAM" * 10) result = schema.execute(""" { foo { text } } """) assert result.data == {"foo": {"text": None}} assert result.errors is None
def test_enum_output(): """Return value from an Enum""" Card = Object( "Card", fields={ "name": str, "color": Color, }, ) schema = Schema() @schema.query.field("random_card") def resolve_random_card(root, info) -> Card: return Card(name="Hello", color=Color.RED) result = schema.execute("{ randomCard { name, color } }") assert result.errors is None assert result.data == {"randomCard": {"name": "Hello", "color": "RED"}}
def test_resolver_can_return_compatible_object(): """ Still a duck. """ schema = Schema() Foo = Object("Foo", {"text": str}) AnotherFoo = namedtuple("AnotherFoo", ("text", )) @schema.query.field("foo") def resolve_foo(root, info) -> Foo: return AnotherFoo(text="a") result = schema.execute(""" { foo { text } } """) assert result.errors is None assert result.data == {"foo": {"text": "a"}}
def test_schema_with_nested_objects(): schema = Schema() Post = Object( "Post", fields={ "title": str, "body": str, }, ) @schema.query.field("post") def resolve_posts(root, info) -> Post: return Post(title="One", body="First post") # ---------------------------------------------------------------- result = schema.execute("{post {title, body}}") assert result.data == {"post": {"title": "One", "body": "First post"}} assert result.errors is None
def test_omitted_fields_are_filled_with_none(): schema = Schema() MyObj = Object( "MyObj", fields={ "foo": str, "bar": str, }, ) @schema.query.field("my_obj") def resolve_my_obj(root, info) -> MyObj: return MyObj(foo="FOO") # ---------------------------------------------------------------- result = schema.execute("{ myObj { foo, bar } }") assert result.errors is None assert result.data == {"myObj": {"foo": "FOO", "bar": None}}
def test_fields_are_converted_to_camel_case(): schema = Schema() MyObject = Object("MyObject", fields={"some_field_name": str}) @schema.query.field("hello") def resolve_hello(root, info) -> MyObject: return MyObject(some_field_name="A VALUE") # ---------------------------------------------------------------- result = schema.execute( """ query { hello { someFieldName } } """ ) assert result.errors is None assert result.data == {"hello": {"someFieldName": "A VALUE"}}
def test_schema_with_nested_objects_list(): schema = Schema() Post = Object( "Post", fields={ "title": str, "body": str, }, ) @schema.query.field("posts") def resolve_posts(root, info) -> List[Post]: return [ Post(title="One", body="First post"), Post(title="Two", body="Second post"), ] # ---------------------------------------------------------------- result = schema.execute("{posts {title, body}}") assert result.data == { "posts": [ { "title": "One", "body": "First post" }, { "title": "Two", "body": "Second post" }, ] } assert result.errors is None
from pyql import Object from app.lib.auth import get_token_for_credentials from .base import schema AuthResult = Object('AuthResult', { 'ok': bool, 'token': str, }) @schema.mutation.field('authenticate') def resolve_auth(root, info, username: str, password: str) -> AuthResult: token = get_token_for_credentials(username, password) if not token: return AuthResult(ok=False, token=None) return AuthResult(ok=True, token=token)
import logging from datetime import datetime from typing import List from pyql import InputObject, Object from app.core.exceptions import UserError from app.core.library import LibraryCore from .base import schema logger = logging.getLogger(__name__) Book = Object('Book', { 'id': int, 'title': str, 'author': str, 'cover_url': str, }) BookRequest = Object('BookRequest', { 'id': int, 'email': str, 'title': str, 'timestamp': datetime, }) @BookRequest.field('timestamp') def resolve_book_request_timestamp(root, info) -> datetime: return root.date_created
from pyql import Object from .base import schema from .user import User Info = Object('Info', { 'version': str, }) @Info.field('user') def resolve_info_user(root, info) -> User: user = info.context.auth_info.user if not user: return None return user @schema.query.field('info') def resolve_info(root, info) -> Info: return Info(version='1.0')
from pyql import InputObject, Object from rx import Observable from app.core.example import NotesCore from app.core.exceptions import UserError from app.lib.graphql import GraphQLFileUpload from .base import schema logger = logging.getLogger(__name__) Note = Object('Note', { 'id': int, 'title': str, 'text': str, }) @Note.field('summary') def resolve_note_summary(note, info, length: int = 100) -> str: if length < 0: raise ValueError('Invalid length: {}'.format(length)) return (note.text or '')[:length] # Note: list ---------------------------------------------------------
def test_container_object_is_instance_of_object(): MyObject = Object("MyObject", fields={"foo": str}) obj = MyObject(foo="A") assert isinstance(obj, MyObject)
from pyql import InputObject, Object from app.core.exceptions import AuthorizationError from app.core.user import UsersCore from .base import schema from .user import User CreateUserInput = InputObject('CreateUserInput', { 'email': str, 'password': str, 'display_name': str, }) CreateUserOutput = Object('CreateUserOutput', { 'ok': bool, 'user': User, }) @schema.mutation.field('create_user') def mut_create_user(root, info, data: CreateUserInput) -> CreateUserOutput: core = UsersCore.from_request() try: uid = core.create(email=data.email, password=data.password, display_name=data.display_name) except AuthorizationError: return CreateUserOutput(ok=False)
from typing import List from pyql import Object from pyql.utils.str_converters import to_camel_case from .fields import AnyValue FormFieldConfig = Object('FormFieldConfig', { 'id': str, 'value': AnyValue, 'readable': bool, 'editable': bool, 'required': bool, }) @FormFieldConfig.field('id') def resolve_formfieldconfig_id(cfg, info) -> str: # This needs to match the field name in javascript return to_camel_case(cfg.id) FormConfig = Object('FormConfig', { 'editable': bool, 'fields': List[FormFieldConfig], })
def test_nested_objects_namespace(): Baz = Object("Baz") @Baz.field("val") def resolve_baz_val(root, info) -> str: return "BAZ-VALUE!" Bar = Object("Bar") Bar.namespace_field("baz", Baz) Foo = Object("Foo") Foo.namespace_field("bar", Bar) Query = Object("Query") Query.namespace_field("foo", Foo) schema = Schema(query=Query) result = schema.execute("{foo {bar {baz {val}}}}") assert result.errors is None assert result.data == {"foo": {"bar": {"baz": {"val": "BAZ-VALUE!"}}}}
from pyql import Object import hashlib from app.utils.normalize import normalize_email_address User = Object('User', { 'id': int, 'email': str, 'display_name': str, 'image_url': str, }) @User.field('display_name') def resolve_display_name(user, info) -> str: if user.display_name: return user.display_name return get_name_from_email(user.email) @User.field('image_url') def resolve_image_url(user, info) -> str: return get_gravatar_url(user.email) def get_name_from_email(email): return email.split('@')[0]