Skip to content

Add document path equivalent to path to ResolveInfo #183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions graphql/execution/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,11 @@ def get_field_entry_key(node):

class ResolveInfo(object):
__slots__ = ('field_name', 'field_asts', 'return_type', 'parent_type',
'schema', 'fragments', 'root_value', 'operation', 'variable_values', 'context', 'path')
'schema', 'fragments', 'root_value', 'operation', 'variable_values',
'context', 'path', 'document_path')

def __init__(self, field_name, field_asts, return_type, parent_type,
schema, fragments, root_value, operation, variable_values, context, path):
schema, fragments, root_value, operation, variable_values, context, path, document_path):
self.field_name = field_name
self.field_asts = field_asts
self.return_type = return_type
Expand All @@ -313,6 +314,7 @@ def __init__(self, field_name, field_asts, return_type, parent_type,
self.variable_values = variable_values
self.context = context
self.path = path
self.document_path = document_path


def default_resolve_fn(source, info, **args):
Expand Down
30 changes: 22 additions & 8 deletions graphql/execution/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ def catch_error(error):
def resolve_field(exe_context, parent_type, source, field_asts, parent_info):
field_ast = field_asts[0]
field_name = field_ast.name.value
field_document_name = field_ast.alias.value if field_ast.alias else field_name

field_def = get_field_def(exe_context.schema, parent_type, field_name)
if not field_def:
Expand Down Expand Up @@ -233,7 +234,8 @@ def resolve_field(exe_context, parent_type, source, field_asts, parent_info):
operation=exe_context.operation,
variable_values=exe_context.variable_values,
context=context,
path=parent_info.path+[field_name] if parent_info else [field_name]
path=parent_info.path + [field_name] if parent_info else [field_name],
document_path=parent_info.document_path + [field_document_name] if parent_info else [field_document_name],
)

executor = exe_context.executor
Expand All @@ -251,6 +253,7 @@ def resolve_field(exe_context, parent_type, source, field_asts, parent_info):
def subscribe_field(exe_context, parent_type, source, field_asts):
field_ast = field_asts[0]
field_name = field_ast.name.value
field_document_name = field_ast.alias.value if field_ast.alias else field_name

field_def = get_field_def(exe_context.schema, parent_type, field_name)
if not field_def:
Expand Down Expand Up @@ -284,7 +287,8 @@ def subscribe_field(exe_context, parent_type, source, field_asts):
operation=exe_context.operation,
variable_values=exe_context.variable_values,
context=context,
path=[field_name]
path=[field_name],
document_path=[field_document_name]
)

executor = exe_context.executor
Expand Down Expand Up @@ -419,16 +423,26 @@ def complete_list_value(exe_context, return_type, field_asts, info, result):
completed_results = []
contains_promise = False

index = 0
path = info.path[:]
for item in result:
info.path = path + [index]
completed_item = complete_value_catching_error(exe_context, item_type, field_asts, info, item)
for index, item in enumerate(result):
item_info = ResolveInfo(
info.field_name,
info.field_asts,
info.return_type,
info.parent_type,
info.schema,
info.fragments,
info.root_value,
info.operation,
info.variable_values,
info.context,
info.path + [index],
info.document_path + [index]
)
completed_item = complete_value_catching_error(exe_context, item_type, field_asts, item_info, item)
if not contains_promise and is_thenable(completed_item):
contains_promise = True

completed_results.append(completed_item)
index += 1

return Promise.all(completed_results) if contains_promise else completed_results

Expand Down
30 changes: 24 additions & 6 deletions graphql/execution/tests/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -745,9 +745,11 @@ def __init__(self, uid, width, height):
class PathCollectorMiddleware(object):
def __init__(self):
self.paths = []
self.document_paths = []

def resolve(self, _next, root, info, *args, **kwargs):
self.paths.append(info.path)
self.document_paths.append(info.document_path)
return _next(root, info, *args, **kwargs)

request = '''
Expand All @@ -757,13 +759,13 @@ def resolve(self, _next, root, info, *args, **kwargs):
...articleFields
author {
id
name
fullName: name
}
},
}
fragment articleFields on Article {
title,
body,
content: body,
hidden,
}
'''
Expand All @@ -778,19 +780,19 @@ def resolve(self, _next, root, info, *args, **kwargs):
{
"id": "1",
"title": "My Article 1",
"body": "This is a post",
"content": "This is a post",
"author": {
"id": "123",
"name": "John Smith"
"fullName": "John Smith"
}
},
{
"id": "2",
"title": "My Article 2",
"body": "This is a post",
"content": "This is a post",
"author": {
"id": "123",
"name": "John Smith"
"fullName": "John Smith"
}
},
],
Expand All @@ -813,3 +815,19 @@ def resolve(self, _next, root, info, *args, **kwargs):
['feed', 1, 'author', 'name']
]

traversed_document_paths = paths_middleware.document_paths
assert traversed_document_paths == [
['feed'],
['feed', 0, 'id'],
['feed', 0, 'title'],
['feed', 0, 'content'],
['feed', 0, 'author'],
['feed', 1, 'id'],
['feed', 1, 'title'],
['feed', 1, 'content'],
['feed', 1, 'author'],
['feed', 0, 'author', 'id'],
['feed', 0, 'author', 'fullName'],
['feed', 1, 'author', 'id'],
['feed', 1, 'author', 'fullName']
]