From 1f541e4467701431687dc1053028712ad74d0c21 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 1 Jul 2018 21:09:12 +0100 Subject: [PATCH] Add crunch utility --- graphene/utils/crunch.py | 37 ++++++++++++++++++++++++++ graphene/utils/tests/test_crunch.py | 40 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 graphene/utils/crunch.py create mode 100644 graphene/utils/tests/test_crunch.py diff --git a/graphene/utils/crunch.py b/graphene/utils/crunch.py new file mode 100644 index 00000000..16902e2b --- /dev/null +++ b/graphene/utils/crunch.py @@ -0,0 +1,37 @@ +import json +from collections import Mapping + + +def to_key(value): + return json.dumps(value) + + +def insert(value, index, values): + key = to_key(value) + + if key not in index: + index[key] = len(values) + values.append(value) + return len(values) - 1 + + return index.get(key) + + +def flatten(data, index, values): + if isinstance(data, (list, tuple)): + flattened = [flatten(child, index, values) for child in data] + elif isinstance(data, Mapping): + flattened = { + key: flatten(child, index, values) for key, child in data.items() + } + else: + flattened = data + return insert(flattened, index, values) + + +def crunch(data): + index = {} + values = [] + + flatten(data, index, values) + return values diff --git a/graphene/utils/tests/test_crunch.py b/graphene/utils/tests/test_crunch.py new file mode 100644 index 00000000..086d0d0f --- /dev/null +++ b/graphene/utils/tests/test_crunch.py @@ -0,0 +1,40 @@ +import pytest + +from ..crunch import crunch + + +@pytest.mark.parametrize("description,uncrunched,crunched", [ + ['number primitive', 0, [0]], + ['boolean primitive', True, [True]], + ['string primitive', "string", ["string"]], + ['empty array', [], [[]]], + ['single-item array', [None], [None, [0]]], + ['multi-primitive all distinct array', [None, 0, True, "string"], [None, 0, True, "string", [0, 1, 2, 3]]], + ['multi-primitive repeated array', [True, True, True, True], [True, [0, 0, 0, 0]]], + ['one-level nested array', [[1, 2, 3]], [1, 2, 3, [0, 1, 2], [3]]], + ['two-level nested array', [[[1, 2, 3]]], [1, 2, 3, [0, 1, 2], [3], [4]]], + ['empty object', {}, [{}]], + ['single-item object', {'a': None}, [None, {'a': 0}]], + [ + 'multi-item all distinct object', + {'a': None, 'b': 0, 'c': True, 'd': "string"}, + [None, 0, True, "string", {'a': 0, 'b': 1, 'c': 2, 'd': 3}] + ], + [ + 'multi-item repeated object', + {'a': True, 'b': True, 'c': True, 'd': True}, + [True, {'a': 0, 'b': 0, 'c': 0, 'd': 0}] + ], + [ + 'complex array', + [{'a': True, 'b': [1, 2, 3]}, [1, 2, 3]], + [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, [5, 4]] + ], + [ + 'complex object', + {'a': True, 'b': [1, 2, 3], 'c': {'a': True, 'b': [1, 2, 3]}}, + [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, {'a': 0, 'b': 4, 'c': 5}] + ], +]) +def test_crunch(description, uncrunched, crunched): + assert crunch(uncrunched) == crunched