Skip to content

Instantly share code, notes, and snippets.

@vmagamedov
Last active December 2, 2017 01:21
Show Gist options
  • Save vmagamedov/41a8c9f60d8cb8109e2441846ef6a06d to your computer and use it in GitHub Desktop.
Save vmagamedov/41a8c9f60d8cb8109e2441846ef6a06d to your computer and use it in GitHub Desktop.
from functools import wraps
import re
from hiku.graph import GraphTransformer, apply
from hiku.graph import Field, Link, Graph, Root, Node, Option
from hiku.types import Sequence, TypeRef
from hiku.query import Field as QueryField
from hiku.engine import Engine
from hiku.result import denormalize
from hiku.executors.sync import SyncExecutor
from hiku.readers.graphql import read
class CamelCaseTransformer(GraphTransformer):
def __init__(self):
self._wrappers = {}
self._inverted = {}
def encode(self, name):
encoded = re.sub('(?:_)(.)', lambda m: m.group(1).upper(), name)
self._inverted[encoded] = name
return encoded
def decorate_field_func(self, func):
wrapper = self._wrappers.get(func)
if wrapper is None:
@wraps(func)
def wrapper(fields, *args):
fields = [QueryField(self._inverted[f.name],
(None if f.options is None
else {self._inverted[k]: v
for k, v in f.options.items()}))
for f in fields]
return func(fields, *args)
wrapper = self._wrappers[func] = wrapper
return wrapper
def decorate_link_func(self, func):
@wraps(func)
def wrapper(*args):
args = list(args)
args[-1] = {self._inverted[k]: v for k, v in args[-1].items()}
return func(*args)
return wrapper
def visit_link(self, obj):
func = self.decorate_link_func(obj.func) if obj.options else obj.func
requires = self.encode(obj.requires) if obj.requires else None
return Link(self.encode(obj.name), obj.type, func,
requires=requires,
options=[self.visit(op) for op in obj.options],
description=obj.description)
def visit_field(self, obj):
return Field(self.encode(obj.name), obj.type,
self.decorate_field_func(obj.func),
options=[self.visit(op) for op in obj.options],
description=obj.description)
def visit_option(self, obj):
return Option(self.encode(obj.name), obj.type, default=obj.default,
description=obj.description)
def foo_fields_loader(fields, ids):
data = {1: {'foo_field': 'foo value 1'},
2: {'foo_field': 'foo value 2'}}
return [[data[i][f.name] for f in fields] for i in ids]
def root_fields_loader(fields):
data = {'root_field': 'root value with {root_option}'}
return [data[f.name].format(**f.options) for f in fields]
GRAPH = Graph([
Node('foo', [
Field('foo_field', None, foo_fields_loader),
]),
Root([
Field('root_field', None, root_fields_loader,
options=[Option('root_option', None)]),
Link('get_foo', Sequence[TypeRef['foo']],
lambda options: options['foo_option'], requires=None,
options=[Option('foo_option', None)]),
])
])
GRAPH = apply(GRAPH, [CamelCaseTransformer()])
engine = Engine(SyncExecutor())
query = read("""
{
rootField(rootOption: 123)
getFoo(fooOption: [2, 1]) {
fooField
}
}
""")
result = engine.execute(GRAPH, query)
plain_result = denormalize(GRAPH, result, query)
assert plain_result == {
'rootField': 'root value with 123',
'getFoo': [
{'fooField': 'foo value 2'},
{'fooField': 'foo value 1'},
]
}
print(plain_result)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment