Эликсир: Использование Absinthe для запроса Dgraph, графической базы данных. Отображение GraphQL в GraphQL+
Я использую Absinthe для создания GraphQL API. Хранилище данных - Dgraph, которое использует GraphQL+ в качестве языка запросов. Он похож на GraphQL, но не идентичен.
Это теоретически поставило бы меня в прекрасную ситуацию. Запрос GraphQL, как
query {
user {
id
username
posts {
title
text
comments {
text
}
}
}
}
может быть также только один запрос в Dgraph. Это выглядело бы почти идентично:
{
users(func: has(type_user))
{
id
username
posts {
title
text
comments {
text
}
}
}
}
Я хотел бы использовать эту мощь графических баз данных для загрузки сложных отношений за один раз. Проблема в том, что в Абсенте схема должна быть составной. В схеме будет один :user
объект, который имеет :posts
поле, которое будет list_of(:post
). А потом :post
объект. И т.д., стр.
Чтобы предотвратить N+1 запросы, вы бы использовали загрузчик данных или пакетную загрузку.
Теперь я могу просто загрузить все за один раз. Я мог бы, например, написать распознаватель, который делает именно это:
defmodule MyApp.Resolvers.User do
alias MyApp.Users
def users(_, _args, _) do
{:ok, Users.all()}
end
end
И пользовательский контекст, который на самом деле запрашивает БД
defmodule MyApp.Users do
alias MyApp.Users.User
def all do
query = """
{
users(func: has(type_user))
{
id
username
posts {
title
text
comments {
text
}
}
}
}
"""
case ExDgraph.query(conn(), query) do
{:ok, msg} ->
%{result: %{users: users}} = msg
Enum.map(users, fn x -> struct(User, x) end)
{:error, _error} ->
[]
end
end
end
Проблема здесь в том, что я перегружен. Я ВСЕГДА запрашиваю все, даже если мне нужен только список пользователей. Это работает, но не очень хорошая производительность. И я теряю способность к компоновке.
Что было бы решением, если бы у меня был доступ к запросу в распознавателе, чтобы понять, какие поля запрашиваются. Затем я мог бы использовать сопоставление с образцом для построения запроса и затем отправить его в Dgraph. Я мог бы даже иметь один центральный преобразователь и много построителей запросов. Но мне нужно подключиться к запросу и разобрать его напрямую.
Возможно ли что-то подобное? Любая идея, где я мог бы найти что-то интересное, чтобы решить эту проблему? Может быть, с промежуточным программным обеспечением абсента?
Спасибо!
1 ответ
Я думаю, что нашел решение. Давайте рассмотрим распознаватель, который выведет вам список пользователей. Что-то вроде этого:
object :user_queries do
field :users, list_of(:user) do
resolve fn _parent, _, resolution ->
IO.inspect(resolution.definition.selections)
{:ok, Users.all()}
end
end
end
Если вы нажмете на него вложенным запросом, например:
{
users {
id
name
posts {
id
title
text
comments {
id
text
}
}
}
}
Вы увидите сложную вложенную карту в терминале. И он содержит всю необходимую нам информацию. Выборы содержат поля. Каждое поле имеет имя. И если у него есть вложенный объект, он снова содержит список selections
,
Теперь нам осталось только пройти путь вниз по кроличьей норе, собрать информацию для нашего запроса Dgraph и построить ее соответствующим образом. И так как он уже прошел проверку Абсента и т. Д., Это выглядит как хороший вариант.
Интересно будет, если подобный подход приведет к проблемам с оптимизацией, с которой приходит Absinthe, например, кешированию в памяти уже извлеченных объектов…