-
-
Notifications
You must be signed in to change notification settings - Fork 135
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
Modify query programmatically #149
Comments
Hi @abitrolly. You can modify the query AST manually, but it is not something you would normally do. Please check the language reference again, sorry it had been broken in Read the Docs lately. Here is how you could solve your two tasks from above: from graphql import (parse, print_ast,
ArgumentNode, NameNode, StringValueNode)
query = """
query getContinents {
continents {
code
name
}
}
"""
# Create AST from source
doc = parse(query)
# Find AST node that needs modification
field = doc.definitions[0].selection_set.selections[0]
# Modify it (add attributes)
field.arguments = [*field.arguments, ArgumentNode(
name=NameNode(value='code'), value=StringValueNode(value='AF'))]
# Print modified AST
new_query = print_ast(doc)
print(new_query) |
@Cito thanks. I still have troubles trying to figure out how to find out the position of element by name and then traverse up the hierarchy. In this particular example I need to find the element named 'code' and then add an attribute to its parent. |
@abitrolly You can use a Visitor to traverse the AST. This will also give you access to the immediate parent and full list of ancestors of the current node. Here is an example of a visitor that searches for a field node with the name 'code', and then adds another field node with the name 'newField' to its parent. from graphql import FieldNode, NameNode, Visitor, parse, print_ast, visit
from graphql.pyutils import FrozenList
query = """
query getContinents {
continents {
code
name
}
}"""
doc = parse(query)
class ExampleVisitor(Visitor):
def enter_name(self, node, key, parent, path, ancestors):
if node.value == 'code' and parent.kind == 'field':
parent = ancestors[-2] # selection set
parent.selections = FrozenList(
(*parent.selections,
FieldNode(name=NameNode(value='newField'))))
return True # stop visiting
visitor = ExampleVisitor()
visit(doc, visitor)
new_query = print_ast(doc)
print(new_query) Note: It is recommended to use a FrozenList instead of an ordinary list to make the nodes hashable. |
I expected some kind of DOM/AST traverse methods, like So the code overwrites
Not Not sure why I need hashable nodes. |
No, something like that doesn't exist in the API. As explained above, the AST is not really meant to be analyzed or modified by users of the API. The visit method is mainly used to implement the various validation rules.
Exactly. The ancestor at -1 (parent) is just the list of field nodes (the selections attribute). You want its parent object which owns this list (selection set node).
It helps to cache nodes during execution. It might also help to detect AST changes and avoid re-validation if that is not the case. |
I still need time to validate how it is going to work. |
@abitrolly I'm currently going through the old tickets before creating the next release. Feel free to reopen or open a new issue if you have concrete questions. |
Sent here from graphql-python/gql#272
There is a way in
gql
to construct queries programmatically with DSL module or by parsing a string into AST withgql.gql()
and then usingprint_ast
fromgraphql
to get back the string.What is not clear is how to actually find nodes in AST and edit or expand them. For example, finding a parent of
node
in the query below (continents
) and adding an attribute to it ((code:"AF")
).So that the query becomes.
I looked into the docs, but it doesn't actually explain.
The documentation container chapter about schemas https://graphql-core-3.readthedocs.io/en/latest/usage/extension.html?highlight=modify%20ast#extending-a-schema and as I am new to GraphQL I am not yet sure if schema and query are the same things.
Feature requests
I am not sure GraphQL.js includes this too and not sure that fundamentally changes the way GraphQL works.
The text was updated successfully, but these errors were encountered: