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 migrator.ex
Raw

lib/migrator.ex

defmodule Neo4Ecto.Migrator do
@moduledoc """
Handles migrations modules loading and version control
"""
alias Neo4Ecto.Migration.Runner
require Logger
## ToDo Reinforce Schema Migration Node Struct
@enforce_keys [:version, :created_at]
defstruct [:version, :created_at]
@migration_path "priv/repo/migrations"
# ToDo use Repo as first parameter in order to get config dir
def run do
migrations_info() |> check_non_executed()
end
def run(:down) do
migrations_info() |> do_run(:down)
end
defp migrations_info, do: Enum.map(migration_files(), &extract_migration_info(&1))
defp get_versions do
{:ok, versions} = Neo4Ecto.execute("MATCH (sm:SCHEMA_MIGRATION) RETURN sm;")
versions
end
defp versions_numbers(versions) do
Enum.map(versions, fn version ->
%{
"sm" => %Bolt.Sips.Types.Node{
properties: %{"version" => version_number}
}
} = version
version_number
end)
end
defp check_non_executed(migrations) do
case get_versions() do
[] -> migrations |> do_run()
versions -> pending_migrations(versions, migrations) |> do_run()
end
end
defp pending_migrations(versions, migrations) do
versions_numbers = versions_numbers(versions)
Enum.filter(migrations, fn {migration_version, _module, _file} ->
migration_version not in versions_numbers
end)
|> case do
[] -> :already_up
migrations -> migrations
end
end
defp do_run(:already_up), do: Logger.info("Migrations already up")
defp do_run(migrations, operation \\ :up)
defp do_run([], _operation), do: Logger.info("Migrations finished")
defp do_run([migration | rest], operation) do
do_run(migration, operation)
do_run(rest, operation)
end
defp do_run({version, module, _file}, operation) do
if Code.ensure_loaded?(module) and
function_exported?(module, operation, 0) do
Runner.run(module, operation, version)
end
end
defp do_compile_migration(file) do
file |> Code.compile_file() |> Enum.map(&elem(&1, 0))
end
# TODO refactor the way we retrieve migrations path (should come from Repo)
# maybe migrator should not call Runner module, but the oposite way (line 76)
defp migration_files do
File.cwd!()
|> Path.join(@migration_path)
|> File.ls!()
end
defp extract_migration_info(file) do
base = Path.basename(file)
full_path_file = Path.join(@migration_path, file)
[module] = do_compile_migration(full_path_file)
case Integer.parse(Path.rootname(base)) do
{integer, "_" <> name} ->
{integer, module, name}
_ ->
nil
end
end
end