Эликсир: Использование 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, например, кешированию в памяти уже извлеченных объектов…

Другие вопросы по тегам