Skip to content
This repository has been archived by the owner on Oct 21, 2022. It is now read-only.

Commit

Permalink
Merge pull request #22 from preply/requires
Browse files Browse the repository at this point in the history
add `@requires` support
  • Loading branch information
erebus1 authored Nov 21, 2019
2 parents 90cedf4 + f7be6dc commit d99613d
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ Supports now:
```
* extend # extend remote types
* external # mark field as external
* requires # mark that field resolver requires other fields to be pre-fetched

Todo implement:
* @requires
* @provides


Expand Down
2 changes: 1 addition & 1 deletion graphene_federation/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .main import key, build_schema
from .extend import extend, external
from .extend import extend, external, requires
5 changes: 5 additions & 0 deletions graphene_federation/extend.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ def decorator(Type):
def external(field):
field._external = True
return field


def requires(field, fields: str):
field._requires = fields
return field
23 changes: 20 additions & 3 deletions graphene_federation/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,36 @@
from .entity import custom_entities


def _mark_external(entity_name, entity, schema, auto_camelcase):
def _mark_field(
entity_name, entity, schema: str, mark_attr_name: str,
decorator_resolver: callable, auto_camelcase: bool
):
for field_name in dir(entity):
field = getattr(entity, field_name, None)
if field is not None and getattr(field, '_external', False):
if field is not None and getattr(field, mark_attr_name, None):
# todo write tests on regexp
schema_field_name = to_camel_case(field_name) if auto_camelcase else field_name
pattern = re.compile(
r"(\s%s\s[^\{]*\{[^\}]*\s%s[\s]*:[\s]*[^\s]+)(\s)" % (
entity_name, schema_field_name))
schema = pattern.sub(r'\g<1> @external ', schema)
schema = pattern.sub(
rf'\g<1> {decorator_resolver(getattr(field, mark_attr_name))} ', schema)

return schema


def _mark_external(entity_name, entity, schema, auto_camelcase):
return _mark_field(
entity_name, entity, schema, '_external', lambda _: '@external', auto_camelcase)


def _mark_requires(entity_name, entity, schema, auto_camelcase):
return _mark_field(
entity_name, entity, schema, '_requires', lambda fields: f'@requires(fields: "{fields}")',
auto_camelcase
)


def get_sdl(schema, custom_entities):
string_schema = str(schema)
string_schema = string_schema.replace("\n", " ")
Expand All @@ -37,6 +53,7 @@ def get_sdl(schema, custom_entities):

for entity_name, entity in extended_types.items():
string_schema = _mark_external(entity_name, entity, string_schema, schema.auto_camelcase)
string_schema = _mark_requires(entity_name, entity, string_schema, schema.auto_camelcase)

type_def_re = r"type %s ([^\{]*)" % entity_name
type_def = r"type %s " % entity_name
Expand Down
7 changes: 6 additions & 1 deletion integration_tests/service_c/src/schema.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from graphene import ObjectType, String, Int, List, NonNull, Field
from graphene_federation import build_schema, extend, external
from graphene_federation import build_schema, extend, external, requires


@extend(fields='id')
class User(ObjectType):
id = external(Int(required=True))
primary_email = external(String())
uppercase_email = requires(String(), fields='primaryEmail')

def resolve_uppercase_email(self, info):
return self.primary_email.upper() if self.primary_email else self.primary_email


class Article(ObjectType):
Expand Down
27 changes: 27 additions & 0 deletions integration_tests/tests/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,30 @@ def test_multiple_key_decorators_apply_multiple_key_annotations():
def test_avoid_duplication_of_key_decorator():
sdl = fetch_sdl('service_a')
assert 'extend type FileNode @key(fields: \"id\") {' in sdl


def test_requires():
query = {
'query': """
query {
articles {
id
text
author {
uppercaseEmail
}
}
}
""",
'variables': {}
}
response = requests.post(
'http://federation:3000/graphql/',
json=query,
)
assert response.status_code == 200
data = json.loads(response.content)['data']
articles = data['articles']

assert articles == [
{'id': 1, 'text': 'some text', 'author': {'uppercaseEmail': 'NAME_5@GMAIL.COM'}}]

0 comments on commit d99613d

Please sign in to comment.