Replies: 6 comments 13 replies
-
This isn't documented (yet!) but its well supported by Ariadne. Only caveat is that this requires your server to be running using ASGI instead of WSGI, so you are having async query executor. Here's python port of dataloader library that is confirmed to work with Ariadne. Example abstraction on top of it could look like this: from aiodataloader import DataLoader
async def get_users_by_id_from_db(ids: Sequence[int]):
data = {u.id: u for u in await some_orm_db_query(id__in=ids)}
return [data.get(i) for i in ids] # this is because dataloader expects sequence of objects or None following order of ids in ids
CONTEXT_KEY = "__users_loader"
def load_user_by_id(info, id: str | int) -> Optional[User]:
if CONTEXT_KEY not in info.context:
info.context[CONTEXT_KEY] = DataLoader(get_users_by_id_from_db)
return info.context[CONTEXT_KEY].load(id)
# GraphQL resolver
def resolve_user(_, info, *, id: str):
return load_user_by_id(info, int(id)) |
Beta Was this translation helpful? Give feedback.
-
In the GraphQL Ruby implementation, they have a concept of "lookahead": https://graphql-ruby.org/queries/lookahead.html#using-a-lookahead It's a helper function to know if a child is requested in the type, at the resolver level. I think it would be a good option for some cases, for example in your case, assuming you are using Django you could do something like: # resolver
def resolve_get_user_carts(_, info):
queryset = Card.objects.get(pk=user_id)
if has_child_field(info, "items", user_id):
queryset = queryset.select_related('items') # or prefetch_related
return queryset I believe |
Beta Was this translation helpful? Give feedback.
-
💩 came looking for the answer to this, but only found out that it isn't really implemented yet |
Beta Was this translation helpful? Give feedback.
-
My particular problem is that we have a resolver that is returning a
and I'm in the resolver for the |
Beta Was this translation helpful? Give feedback.
-
Crazy as this may seem, this works: from graphql import FieldNode, GraphQLResolveInfo, SelectionNode, SelectionSetNode
def _find_field(name: str, fields: Iterable[FieldNode]) -> Optional[FieldNode]:
for node in fields:
if node.name.value == name:
return node
# Couldn't find the node.
return None
def _get_field_nodes(fields: Iterable[SelectionNode]) -> list[FieldNode]:
return [node for node in fields if isinstance(node, FieldNode)]
def look_ahead_fields(info: GraphQLResolveInfo, *names: str) -> list[str]:
# There is always one `field_nodes` and it is the AST of the current field.
return [
node.name.value
for node in _look_ahead_fields(info.field_nodes[0].selection_set, names)
]
def look_ahead_field(info: GraphQLResolveInfo, *names: str) -> Optional[FieldNode]:
look_ahead = cast(tuple[str], names[:-1])
if look_ahead:
fields = _look_ahead_fields(info.field_nodes[0].selection_set, look_ahead)
else:
selection_set = info.field_nodes[0].selection_set
if selection_set is None:
return None
fields = _get_field_nodes(selection_set.selections)
return _find_field(names[-1], fields)
def _look_ahead_fields(
fields: Optional[SelectionSetNode], names: tuple[str]
) -> list[FieldNode]:
if not names or not fields:
return []
field_name = names[0]
field = _find_field(field_name, _get_field_nodes(fields.selections))
if not field or field.selection_set is None:
return []
# If there are more names, walk down, otherwise return the names of the fields.
if len(names) > 1:
return _look_ahead_fields(field.selection_set, cast(tuple[str], names[1:]))
return _get_field_nodes(field.selection_set.selections) If I'm in the resolver for and
|
Beta Was this translation helpful? Give feedback.
-
Not 100% sure that this discussion is suitable, but will try to post my question here. create table authors(name text primary key);
create table books(title text primary key, author text not null references authors(name)); And my graphql schema will be like: type Query{
authors: [Author!]!
}
type Author{
name: String!
books: [Book!]!
}
type Book{
title: String!
} Ariadne doc says:
So, according to this, to retrieve all books for author with dataloader, I must first retrieve book titles: async def get_books(titles: list[str]) -> list[Book]:
return order_books_according_to_titles(await fetch_books_by_titles(titles), titles) Or it is ok to use dataloader with author name for books fetch? Something like this: async def get_books(author_names: list[str]) -> list[Book]:
return order_books_according_to_author_names(await fetch_books_by_author_names(author_names), author_names) |
Beta Was this translation helpful? Give feedback.
-
Anybody have good libraries/patterns for dealing with fetching data from remote sources like DBs to reduce number of queries?
example:
In a suboptimal approach to implementing
getUserCarts
this would query the database for all carts, then an additional query for each cart to query cart items.Preferred approach would be to collect all the Cart IDs and then batch load all the cart items in one query...
Anyone implement something like this for Ariadne?
Beta Was this translation helpful? Give feedback.
All reactions