Эликсир: Использование Absinthe для запроса Dgraph, графической базы данных.Отображение GraphQL в GraphQL + - PullRequest
0 голосов
/ 04 июня 2018

Я использую 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

И пользовательский контекст, который фактически запрашивает db

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 Ответ

0 голосов
/ 05 июня 2018

Я думаю, что нашел решение.Давайте рассмотрим распознаватель, который выдаст вам список пользователей.Примерно так:

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 и построить ее соответствующим образом.И так как он уже прошел проверку Абсента и т. Д., Он выглядит как хороший вариант.

Интересно будет, если подобный подход приведет к проблемам с оптимизацией, с которой приходит Абсент, например, в кешировании памяти уже извлеченных объектов...

...