Packages

Neo4Ecto is an Ecto adapter that sits on top of Bolt.Sips driver and Ecto Data Mapping Tool Kit.

Current section

Files

Jump to
neo4_ecto lib storage.ex
Raw

lib/storage.ex

defmodule Neo4Ecto.Storage do
@moduledoc """
Storage Adapter module for Neo4j.
"""
@behaviour Ecto.Adapter.Storage
import Mix.Ecto
@impl true
def storage_up(opts) do
database =
Keyword.fetch!(opts, :database) || raise ":database is nil in repository configuration"
check_database_exists_command = "SHOW DATABASES WHERE name = '#{database}'"
repo = ensure_repo_started(opts)
case run_command(check_database_exists_command, repo) do
{:ok, []} ->
create_database_command = "CREATE DATABASE #{database};"
case run_command(create_database_command, repo) do
{:ok, _} ->
:ok
{:error, error} ->
{:error, Exception.message(error)}
end
_ ->
{:error, :already_up}
end
end
@impl true
def storage_down(opts) do
repo = ensure_repo_started(opts)
database =
Keyword.fetch!(opts, :database) || raise ":database is nil in repository configuration"
drop_database_command = "DROP DATABASE #{database};"
case run_command(drop_database_command, repo) do
{:ok, _} ->
:ok
{:error, error} ->
{:error, error}
end
end
@impl true
def storage_status(opts) do
repo = ensure_repo_started(opts)
database =
Keyword.fetch!(opts, :database) || raise ":database is nil in repository configuration"
check_database_status = "SHOW DATABASES WHERE name = '#{database}'"
case run_command(check_database_status, repo) do
{:ok, []} -> :down
{:ok, _result} -> :up
error -> {:error, error}
end
end
defp run_command(cypher, repo) do
case run_query(cypher, repo) do
{:ok, %Bolt.Sips.Response{results: results}} ->
{:ok, results}
{:ok, %Bolt.Sips.Response{stats: %{"system-updates" => 1}}} ->
{:ok, :executed}
{:error,
%Bolt.Sips.Error{
code: "Neo.ClientError.Database.DatabaseNotFound"
}} ->
{:error, :already_down}
end
end
defp run_query(cypher, repo) do
case repo.start_link() do
{:ok, bolt_pid} ->
conn = Bolt.Sips.conn()
result = Bolt.Sips.query(conn, cypher)
GenServer.stop(bolt_pid)
result
{:error, _} = error ->
Mix.raise("Could not start repo #{inspect(repo)} error: #{inspect(error)}")
end
end
defp ensure_repo_started(opts) do
[repo] = parse_repo(opts)
{:ok, _started} = Application.ensure_all_started(:neo4_ecto)
ensure_repo(repo, opts)
repo
end
end