Merge pull request #786 from jkimbo/deduplicator

Deduplicator
This commit is contained in:
Syrus Akbary 2018-07-01 18:10:36 -07:00 committed by GitHub
commit 2e41db8d95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 295 additions and 0 deletions

View File

@ -0,0 +1,38 @@
from collections import Mapping, OrderedDict
def deflate(node, index=None, path=None):
if index is None:
index = {}
if path is None:
path = []
if node and 'id' in node and '__typename' in node:
route = ','.join(path)
cache_key = ':'.join([route, str(node['__typename']), str(node['id'])])
if index.get(cache_key) is True:
return {
'__typename': node['__typename'],
'id': node['id'],
}
else:
index[cache_key] = True
field_names = node.keys()
result = OrderedDict()
for field_name in field_names:
value = node[field_name]
new_path = path + [field_name]
if isinstance(value, (list, tuple)):
result[field_name] = [
deflate(child, index, new_path) for child in value
]
elif isinstance(value, Mapping):
result[field_name] = deflate(value, index, new_path)
else:
result[field_name] = value
return result

View File

@ -0,0 +1,257 @@
import datetime
import graphene
from graphene import relay
from graphene.types.resolver import dict_resolver
from ..deduplicator import deflate
def test_does_not_modify_object_without_typename_and_id():
response = {
'foo': 'bar',
}
deflated_response = deflate(response)
assert deflated_response == {
'foo': 'bar',
}
def test_does_not_modify_first_instance_of_an_object():
response = {
'data': [
{
'__typename': 'foo',
'id': 1,
'name': 'foo'
},
{
'__typename': 'foo',
'id': 1,
'name': 'foo'
}
]
}
deflated_response = deflate(response)
assert deflated_response == {
'data': [
{
'__typename': 'foo',
'id': 1,
'name': 'foo'
},
{
'__typename': 'foo',
'id': 1
}
]
}
def test_does_not_modify_first_instance_of_an_object_nested():
response = {
'data': [
{
'__typename': 'foo',
'bar1': {
'__typename': 'bar',
'id': 1,
'name': 'bar'
},
'bar2': {
'__typename': 'bar',
'id': 1,
'name': 'bar'
},
'id': 1
},
{
'__typename': 'foo',
'bar1': {
'__typename': 'bar',
'id': 1,
'name': 'bar'
},
'bar2': {
'__typename': 'bar',
'id': 1,
'name': 'bar'
},
'id': 2
}
]
}
deflated_response = deflate(response)
assert deflated_response == {
'data': [
{
'__typename': 'foo',
'bar1': {
'__typename': 'bar',
'id': 1,
'name': 'bar'
},
'bar2': {
'__typename': 'bar',
'id': 1,
'name': 'bar'
},
'id': 1
},
{
'__typename': 'foo',
'bar1': {
'__typename': 'bar',
'id': 1
},
'bar2': {
'__typename': 'bar',
'id': 1
},
'id': 2
}
]
}
def test_does_not_modify_input():
response = {
'data': [
{
'__typename': 'foo',
'id': 1,
'name': 'foo'
},
{
'__typename': 'foo',
'id': 1,
'name': 'foo'
}
]
}
deflate(response)
assert response == {
'data': [
{
'__typename': 'foo',
'id': 1,
'name': 'foo'
},
{
'__typename': 'foo',
'id': 1,
'name': 'foo'
}
]
}
TEST_DATA = {
'events': [
{
'id': '568',
'date': datetime.date(2017, 5, 19),
'movie': '1198359',
},
{
'id': '234',
'date': datetime.date(2017, 5, 20),
'movie': '1198359',
},
],
'movies': {
'1198359': {
'name': 'King Arthur: Legend of the Sword',
'synopsis': (
"When the child Arthur's father is murdered, Vortigern, "
"Arthur's uncle, seizes the crown. Robbed of his birthright and "
"with no idea who he truly is..."
),
},
},
}
def test_example_end_to_end():
class Movie(graphene.ObjectType):
class Meta:
interfaces = (relay.Node,)
default_resolver = dict_resolver
name = graphene.String(required=True)
synopsis = graphene.String(required=True)
class Event(graphene.ObjectType):
class Meta:
interfaces = (relay.Node,)
default_resolver = dict_resolver
movie = graphene.Field(Movie, required=True)
date = graphene.types.datetime.Date(required=True)
def resolve_movie(event, info):
return TEST_DATA['movies'][event['movie']]
class Query(graphene.ObjectType):
events = graphene.List(
graphene.NonNull(Event),
required=True
)
def resolve_events(_, info):
return TEST_DATA['events']
schema = graphene.Schema(query=Query)
query = """\
{
events {
__typename
id
date
movie {
__typename
id
name
synopsis
}
}
}
"""
result = schema.execute(query)
assert not result.errors
result.data = deflate(result.data)
assert result.data == {
'events': [
{
'__typename': 'Event',
'id': 'RXZlbnQ6NTY4',
'date': '2017-05-19',
'movie': {
'__typename': 'Movie',
'id': 'TW92aWU6Tm9uZQ==',
'name': 'King Arthur: Legend of the Sword',
'synopsis': (
"When the child Arthur's father is murdered, Vortigern, "
"Arthur's uncle, seizes the crown. Robbed of his birthright and "
"with no idea who he truly is..."
),
},
},
{
'__typename': 'Event',
'id': 'RXZlbnQ6MjM0',
'date': '2017-05-20',
'movie': {
'__typename': 'Movie',
'id': 'TW92aWU6Tm9uZQ==',
},
},
],
}