Packages
ecto_tablestore
0.5.9
0.15.1
0.15.0
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.1
0.10.0
0.9.0
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.1
0.6.0
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.0
Alibaba Tablestore adapter for Ecto
Current section
Files
Jump to
Current section
Files
lib/ecto_tablestore/migration/runner.ex
defmodule EctoTablestore.Migration.Runner do
@moduledoc false
use Agent, restart: :temporary
alias EctoTablestore.Migration.Table
require Logger
def run(repo, version, module, operation, opts) do
level = Keyword.get(opts, :log, :info)
log = %{level: level}
args = {self(), repo, module, log}
{:ok, runner} =
DynamicSupervisor.start_child(EctoTablestore.MigratorSupervisor, {__MODULE__, args})
metadata(runner, opts)
log(level, "== Running #{version} #{inspect(module)}.#{operation}/0")
{time, _} = :timer.tc(fn -> perform_operation(module, operation) end)
log(level, "== Migrated #{version} in #{inspect(div(time, 100_000) / 10)}s")
stop()
end
def start_link({parent, repo, module, log}) do
Agent.start_link(fn ->
Process.link(parent)
%{
repo: repo,
migration: module,
command: nil,
subcommands: [],
commands: [],
log: log,
config: repo.config()
}
end)
end
def end_command do
Agent.update(runner(), fn state ->
{operation, object} = state.command
command = {operation, object, Enum.reverse(state.subcommands)}
%{state | command: nil, subcommands: [], commands: [command | state.commands]}
end)
end
def subcommand(subcommand) do
reply =
Agent.get_and_update(runner(), fn
%{command: nil} = state ->
{:error, state}
state ->
{:ok, update_in(state.subcommands, &[subcommand | &1])}
end)
case reply do
:ok ->
:ok
:error ->
raise Ecto.MigrationError, message: "cannot execute command outside of block"
end
end
def execute(command) do
reply =
Agent.get_and_update(runner(), fn
%{command: nil} = state ->
{:ok, %{state | subcommands: [], commands: [command | state.commands]}}
%{command: _} = state ->
{:error, %{state | command: nil}}
end)
case reply do
:ok ->
:ok
:error ->
raise Ecto.MigrationError, "cannot execute nested commands"
end
end
def start_command(command) do
reply =
Agent.get_and_update(runner(), fn
%{command: nil} = state ->
{:ok, %{state | command: command}}
%{command: _} = state ->
{:error, %{state | command: command}}
end)
case reply do
:ok ->
:ok
:error ->
raise Ecto.MigrationError, "cannot execute nested commands"
end
end
def repo do
Agent.get(runner(), & &1.repo)
end
def prefix do
case Process.get(:ecto_tablestore_migration) do
%{prefix: prefix} -> prefix
_ -> "could not find migration runner process for #{inspect(self())}"
end
end
def repo_config(key, default) do
Agent.get(runner(), &Keyword.get(&1.config, key, default))
end
defp perform_operation(module, operation) do
apply(module, operation, [])
flush()
end
defp stop() do
Agent.stop(runner())
end
defp metadata(runner, opts) do
prefix = opts[:prefix]
Process.put(:ecto_tablestore_migration, %{runner: runner, prefix: prefix && to_string(prefix)})
end
defp log(false, _msg), do: :ok
defp log(level, msg), do: Logger.log(level, msg)
defp runner do
case Process.get(:ecto_tablestore_migration) do
%{runner: runner} -> runner
_ -> raise "could not find migration runner process for #{inspect(self())}"
end
end
defp flush do
%{commands: commands, repo: repo, log: _level, migration: _migration} =
Agent.get_and_update(runner(), fn state -> {state, %{state | commands: []}} end)
for command <- commands do
do_execute(repo, command)
end
end
defp do_execute(repo, {:create, %Table{} = _table, columns} = command)
when length(columns) <= 4 do
command = verify_command_to_table(command)
repo.__adapter__.execute_ddl(repo, command)
end
defp do_execute(_repo, {:create, _table, columns}) do
raise Ecto.MigrationError,
message:
"can only have up to 4 primary keys, but get #{length(columns)} primary keys: #{
inspect(columns)
}"
end
defp verify_command_to_table({:create, %Table{partition_key: true} = _table, columns} = command)
when length(columns) == 1 do
command
end
defp verify_command_to_table({:create, %Table{partition_key: true} = table, columns} = command)
when length(columns) > 1 do
[_auto_generated_id_col, {_, _field_name, _field_type, opts} | _] = columns
# Use defined partition key to instead of the auto generated.
if Keyword.get(opts, :partition_key, false) do
{:create, table, List.delete_at(columns, 0)}
else
command
end
end
defp verify_command_to_table(
{:create, %Table{partition_key: false} = _table, _columns} = command
) do
command
end
end