graphql-epoxy
Advanced tools
@@ -113,14 +113,11 @@ from bisect import bisect_left, bisect_right | ||
| begin_key = cursor.get_offset(after, None) or self._keys[0] | ||
| end_key = cursor.get_offset(before, None) or self._keys[-1] | ||
| begin_key = cursor.get_offset(after, None) | ||
| end_key = cursor.get_offset(before, None) | ||
| begin = self.bisect_left(begin_key) | ||
| end = self.bisect_right(end_key) | ||
| lower_bound = begin = self.bisect_left(begin_key) + 1 if begin_key else 0 | ||
| upper_bound = end = self.bisect_right(end_key) - 1 if end_key else count | ||
| if begin >= count or begin >= end: | ||
| return self.empty_connection(relay, type_name) | ||
| if upper_bound < count and self._keys[upper_bound] != end_key: | ||
| upper_bound = end = count | ||
| first_preslice_cursor = cursor.from_offset(self._keys[begin]) | ||
| last_preslice_cursor = cursor.from_offset(self._keys[min(end, count) - 1]) | ||
| if first is not None: | ||
@@ -131,10 +128,7 @@ end = min(begin + first, end) | ||
| if begin >= count or begin >= end: | ||
| return self.empty_connection(relay, type_name) | ||
| sliced_data = self._items[begin:end] | ||
| edges = [Edge(node=node, cursor=cursor.from_offset(self._key(node))) for node in sliced_data] | ||
| first_edge = edges[0] | ||
| last_edge = edges[-1] | ||
| first_edge = edges[0] if edges else None | ||
| last_edge = edges[-1] if edges else None | ||
@@ -144,7 +138,7 @@ return Connection( | ||
| page_info=relay.PageInfo( | ||
| start_cursor=first_edge.cursor, | ||
| end_cursor=last_edge.cursor, | ||
| has_previous_page=(first_edge.cursor != first_preslice_cursor), | ||
| has_next_page=(last_edge.cursor != last_preslice_cursor) | ||
| start_cursor=first_edge and first_edge.cursor, | ||
| end_cursor=last_edge and last_edge.cursor, | ||
| has_previous_page=begin > lower_bound, | ||
| has_next_page=end < upper_bound | ||
| ) | ||
| ) |
| Metadata-Version: 1.1 | ||
| Name: graphql-epoxy | ||
| Version: 0.1a1 | ||
| Version: 0.2a0 | ||
| Summary: GraphQL implementation for Python | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/graphql-python/graphql-core |
+1
-1
| Metadata-Version: 1.1 | ||
| Name: graphql-epoxy | ||
| Version: 0.1a1 | ||
| Version: 0.2a0 | ||
| Summary: GraphQL implementation for Python | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/graphql-python/graphql-core |
+2
-2
@@ -6,5 +6,5 @@ [flake8] | ||
| [egg_info] | ||
| tag_svn_revision = 0 | ||
| tag_build = | ||
| tag_date = 0 | ||
| tag_build = | ||
| tag_svn_revision = 0 | ||
+1
-1
@@ -14,3 +14,3 @@ from setuptools import setup, find_packages | ||
| name='graphql-epoxy', | ||
| version='0.1a1', | ||
| version='0.2a0', | ||
| description='GraphQL implementation for Python', | ||
@@ -17,0 +17,0 @@ url='https://github.com/graphql-python/graphql-core', |
@@ -7,11 +7,3 @@ from graphql.core import graphql | ||
| pet_names = ["Max", "Buddy", "Charlie", "Jack", "Cooper", "Rocky", "Toby", "Tucker", "Jake", "Bear", "Duke", "Teddy", | ||
| "Oliver", "Riley", "Bailey", "Bentley", "Milo", "Buster", "Cody", "Dexter", "Winston", "Murphy", "Leo", | ||
| "Lucky", "Oscar", "Louie", "Zeus", "Henry", "Sam", "Harley", "Baxter", "Gus", "Sammy", "Jackson", "Bruno", | ||
| "Diesel", "Jax", "Gizmo", "Bandit", "Rusty", "Marley", "Jasper", "Brody", "Roscoe", "Hank", "Otis", "Bo", | ||
| "Joey", "Beau", "Ollie", "Tank", "Shadow", "Peanut", "Hunter", "Scout", "Blue", "Rocco", "Simba", "Tyson", | ||
| "Ziggy", "Boomer", "Romeo", "Apollo", "Ace", "Luke", "Rex", "Finn", "Chance", "Rudy", "Loki", "Moose", | ||
| "George", "Samson", "Coco", "Benny", "Thor", "Rufus", "Prince", "Chester", "Brutus", "Scooter", "Chico", | ||
| "Spike", "Gunner", "Sparky", "Mickey", "Kobe", "Chase", "Oreo", "Frankie", "Mac", "Benji", "Bubba", | ||
| "Champ", "Brady", "Elvis", "Copper", "Cash", "Archie", "Walter"] | ||
| letter_chars = ['A', 'B', 'C', 'D', 'E'] | ||
@@ -24,8 +16,8 @@ data_source = InMemoryDataSource() | ||
| class Pet(R.Implements[Relay.Node]): | ||
| name = R.String | ||
| class Letter(R.Implements[Relay.Node]): | ||
| letter = R.String | ||
| class Query(R.ObjectType): | ||
| pets = Relay.Connection('Pet', R.Pet) | ||
| letters = Relay.Connection('Letter', R.Letter) | ||
| node = Relay.NodeField | ||
@@ -36,65 +28,38 @@ | ||
| pets = [] | ||
| for i, pet_name in enumerate(pet_names, 1): | ||
| pet = Pet(id=i, name=pet_name) | ||
| pets.append(pet) | ||
| data_source.add(pet) | ||
| letters = {} | ||
| for i, letter in enumerate(letter_chars, 1): | ||
| l = Letter(id=i, letter=letter) | ||
| letters[letter] = l | ||
| data_source.add(l) | ||
| def test_query_pets_all(): | ||
| result = graphql(Schema, ''' | ||
| { | ||
| pets { | ||
| edges { | ||
| node { | ||
| id | ||
| name | ||
| } | ||
| cursor | ||
| } | ||
| pageInfo { | ||
| hasPreviousPage | ||
| hasNextPage | ||
| startCursor | ||
| endCursor | ||
| } | ||
| } | ||
| } | ||
| ''') | ||
| expected_edges = [ | ||
| def edges(selected_letters): | ||
| return [ | ||
| { | ||
| 'node': { | ||
| 'id': base64('Pet:%s' % p.id), | ||
| 'name': p.name | ||
| 'id': base64('Letter:%s' % l.id), | ||
| 'letter': l.letter | ||
| }, | ||
| 'cursor': base64('sc:%s' % p.id) | ||
| 'cursor': base64('sc:%s' % l.id) | ||
| } | ||
| for p in pets | ||
| ] | ||
| for l in [letters[i] for i in selected_letters] | ||
| ] | ||
| expected_page_info = { | ||
| 'hasNextPage': False, | ||
| 'hasPreviousPage': False, | ||
| 'endCursor': expected_edges[-1]['cursor'], | ||
| 'startCursor': expected_edges[0]['cursor'] | ||
| } | ||
| assert not result.errors | ||
| assert result.data == { | ||
| 'pets': { | ||
| 'edges': expected_edges, | ||
| 'pageInfo': expected_page_info | ||
| } | ||
| } | ||
| def cursor_for(ltr): | ||
| l = letters[ltr] | ||
| return base64('sc:%s' % l.id) | ||
| def test_query_pets_first_5(): | ||
| result = graphql(Schema, ''' | ||
| def execute(args=''): | ||
| if args: | ||
| args = '(' + args + ')' | ||
| return graphql(Schema, ''' | ||
| { | ||
| pets(first: 5) { | ||
| letters%s { | ||
| edges { | ||
| node { | ||
| id | ||
| name | ||
| letter | ||
| } | ||
@@ -111,20 +76,13 @@ cursor | ||
| } | ||
| ''') | ||
| ''' % args) | ||
| expected_edges = [ | ||
| { | ||
| 'node': { | ||
| 'id': base64('Pet:%s' % p.id), | ||
| 'name': p.name | ||
| }, | ||
| 'cursor': base64('sc:%s' % p.id) | ||
| } | ||
| for p in pets[:5] | ||
| ] | ||
| def check(args, letters, has_previous_page=False, has_next_page=False): | ||
| result = execute(args) | ||
| expected_edges = edges(letters) | ||
| expected_page_info = { | ||
| 'hasNextPage': True, | ||
| 'hasPreviousPage': False, | ||
| 'endCursor': expected_edges[-1]['cursor'], | ||
| 'startCursor': expected_edges[0]['cursor'] | ||
| 'hasPreviousPage': has_previous_page, | ||
| 'hasNextPage': has_next_page, | ||
| 'endCursor': expected_edges[-1]['cursor'] if expected_edges else None, | ||
| 'startCursor': expected_edges[0]['cursor'] if expected_edges else None | ||
| } | ||
@@ -134,3 +92,3 @@ | ||
| assert result.data == { | ||
| 'pets': { | ||
| 'letters': { | ||
| 'edges': expected_edges, | ||
@@ -142,193 +100,75 @@ 'pageInfo': expected_page_info | ||
| def test_query_pets_last_5(): | ||
| result = graphql(Schema, ''' | ||
| { | ||
| pets(last: 5) { | ||
| edges { | ||
| node { | ||
| id | ||
| name | ||
| } | ||
| cursor | ||
| } | ||
| pageInfo { | ||
| hasPreviousPage | ||
| hasNextPage | ||
| startCursor | ||
| endCursor | ||
| } | ||
| } | ||
| } | ||
| ''') | ||
| def test_returns_all_elements_without_filters(): | ||
| check('', 'ABCDE') | ||
| expected_edges = [ | ||
| { | ||
| 'node': { | ||
| 'id': base64('Pet:%s' % p.id), | ||
| 'name': p.name | ||
| }, | ||
| 'cursor': base64('sc:%s' % p.id) | ||
| } | ||
| for p in pets[-5:] | ||
| ] | ||
| expected_page_info = { | ||
| 'hasNextPage': False, | ||
| 'hasPreviousPage': True, | ||
| 'endCursor': expected_edges[-1]['cursor'], | ||
| 'startCursor': expected_edges[0]['cursor'] | ||
| } | ||
| def test_respects_a_smaller_first(): | ||
| check('first: 2', 'AB', has_next_page=True) | ||
| assert not result.errors | ||
| assert result.data == { | ||
| 'pets': { | ||
| 'edges': expected_edges, | ||
| 'pageInfo': expected_page_info | ||
| } | ||
| } | ||
| def test_respects_an_overly_large_first(): | ||
| check('first: 10', 'ABCDE') | ||
| def test_query_pets_first_10_last_5(): | ||
| result = graphql(Schema, ''' | ||
| { | ||
| pets(first: 10, last: 5) { | ||
| edges { | ||
| node { | ||
| id | ||
| name | ||
| } | ||
| cursor | ||
| } | ||
| pageInfo { | ||
| hasPreviousPage | ||
| hasNextPage | ||
| startCursor | ||
| endCursor | ||
| } | ||
| } | ||
| } | ||
| ''') | ||
| expected_edges = [ | ||
| { | ||
| 'node': { | ||
| 'id': base64('Pet:%s' % p.id), | ||
| 'name': p.name | ||
| }, | ||
| 'cursor': base64('sc:%s' % p.id) | ||
| } | ||
| for p in pets[:10][-5:] | ||
| ] | ||
| def test_respects_a_smaller_last(): | ||
| check('last: 2', 'DE', has_previous_page=True) | ||
| expected_page_info = { | ||
| 'hasNextPage': True, | ||
| 'hasPreviousPage': True, | ||
| 'endCursor': expected_edges[-1]['cursor'], | ||
| 'startCursor': expected_edges[0]['cursor'] | ||
| } | ||
| assert not result.errors | ||
| assert result.data == { | ||
| 'pets': { | ||
| 'edges': expected_edges, | ||
| 'pageInfo': expected_page_info | ||
| } | ||
| } | ||
| def test_respects_an_overly_large_last(): | ||
| check('last: 10', 'ABCDE') | ||
| def test_after_cursor(): | ||
| result = graphql(Schema, ''' | ||
| { | ||
| pets(first: 10, after: "c2M6MTA=") { | ||
| edges { | ||
| node { | ||
| id | ||
| name | ||
| } | ||
| cursor | ||
| } | ||
| pageInfo { | ||
| hasPreviousPage | ||
| hasNextPage | ||
| startCursor | ||
| endCursor | ||
| } | ||
| } | ||
| } | ||
| ''') | ||
| def test_respects_first_and_after(): | ||
| check('first: 2, after: "{}"'.format(cursor_for('B')), 'CD', has_next_page=True) | ||
| expected_edges = [ | ||
| { | ||
| 'node': { | ||
| 'id': base64('Pet:%s' % p.id), | ||
| 'name': p.name | ||
| }, | ||
| 'cursor': base64('sc:%s' % p.id) | ||
| } | ||
| for p in pets[9:19] | ||
| ] | ||
| assert len(expected_edges) == 10 | ||
| expected_page_info = { | ||
| 'hasNextPage': True, | ||
| 'hasPreviousPage': False, | ||
| 'endCursor': expected_edges[-1]['cursor'], | ||
| 'startCursor': expected_edges[0]['cursor'] | ||
| } | ||
| def test_respects_first_and_after_with_long_first(): | ||
| check('first: 10, after: "{}"'.format(cursor_for('B')), 'CDE') | ||
| assert not result.errors | ||
| assert result.data == { | ||
| 'pets': { | ||
| 'edges': expected_edges, | ||
| 'pageInfo': expected_page_info | ||
| } | ||
| } | ||
| def test_respects_last_and_before(): | ||
| check('last: 2, before: "{}"'.format(cursor_for('D')), 'BC', has_previous_page=True) | ||
| def test_before_cursor(): | ||
| result = graphql(Schema, ''' | ||
| { | ||
| pets(first: 10, before: "c2M6MTA=") { | ||
| edges { | ||
| node { | ||
| id | ||
| name | ||
| } | ||
| cursor | ||
| } | ||
| pageInfo { | ||
| hasPreviousPage | ||
| hasNextPage | ||
| startCursor | ||
| endCursor | ||
| } | ||
| } | ||
| } | ||
| ''') | ||
| expected_edges = [ | ||
| { | ||
| 'node': { | ||
| 'id': base64('Pet:%s' % p.id), | ||
| 'name': p.name | ||
| }, | ||
| 'cursor': base64('sc:%s' % p.id) | ||
| } | ||
| for p in pets[:10] | ||
| ] | ||
| def test_respects_last_and_before_with_long_last(): | ||
| check('last: 10, before: "{}"'.format(cursor_for('D')), 'ABC') | ||
| assert len(expected_edges) == 10 | ||
| expected_page_info = { | ||
| 'hasNextPage': False, | ||
| 'hasPreviousPage': False, | ||
| 'endCursor': expected_edges[-1]['cursor'], | ||
| 'startCursor': expected_edges[0]['cursor'] | ||
| } | ||
| assert not result.errors | ||
| assert result.data == { | ||
| 'pets': { | ||
| 'edges': expected_edges, | ||
| 'pageInfo': expected_page_info | ||
| } | ||
| } | ||
| def test_respects_first_and_after_and_before_too_few(): | ||
| check('first: 2, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'BC', has_next_page=True) | ||
| def test_respects_first_and_after_and_before_too_many(): | ||
| check('first: 4, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'BCD') | ||
| def test_respects_first_and_after_and_before_exactly_right(): | ||
| check('first: 3, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), "BCD") | ||
| def test_respects_last_and_after_and_before_too_few(): | ||
| check('last: 2, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'CD', has_previous_page=True) | ||
| def test_respects_last_and_after_and_before_too_many(): | ||
| check('last: 4, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'BCD') | ||
| def test_respects_last_and_after_and_before_exactly_right(): | ||
| check('last: 3, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'BCD') | ||
| def test_returns_no_elements_if_first_is_0(): | ||
| check('first: 0', '', has_next_page=True) | ||
| def test_returns_all_elements_if_cursors_are_invalid(): | ||
| check('before: "invalid" after: "invalid"', 'ABCDE') | ||
| def test_returns_all_elements_if_cursors_are_on_the_outside(): | ||
| check('before: "{}" after: "{}"'.format(base64('sc:%s' % 6), base64('sc:%s' % 0)), 'ABCDE') | ||
| def test_returns_no_elements_if_cursors_cross(): | ||
| check('before: "{}" after: "{}"'.format(base64('sc:%s' % 2), base64('sc:%s' % 4)), '') |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
57270
-5.97%1488
-10.9%