Packages

Comparator for OTS(Aliyun Tablestore Database)

Current section

Files

Jump to
ots_comparator lib cli.ex
Raw

lib/cli.ex

defmodule OtsComparator.Cli do
@moduledoc false
def cli_compare(config_path, instance_a, instance_b)
when is_binary(config_path) and is_binary(instance_a) and is_binary(instance_b) do
Config.Reader.read!(config_path)
|> Application.put_all_env()
Application.ensure_all_started(:ex_aliyun_ots)
cli_compare(instance_a, instance_b)
end
def cli_compare(instance_a, instance_b) do
OtsComparator.compare(
String.to_existing_atom(instance_a),
String.to_existing_atom(instance_b)
)
|> format(instance_a, instance_b)
end
def format(
%{
count: {count_a, count_b},
count_diff: count_diff,
table_diff: table_diff,
table_content_diff: table_content_diff
},
instance_a,
instance_b
) do
[
"",
"Instance:#{instance_a}, count: #{count_a}",
"Instance:#{instance_b}, count: #{count_b}",
"Count diff: #{count_diff}",
"",
"#{instance_a} VS #{instance_b}",
format_list_diff(table_diff),
format_table_content_diff(table_content_diff)
]
|> Stream.reject(&is_nil/1)
|> Enum.intersperse("\n")
|> IO.iodata_to_binary()
|> IO.puts()
end
def format_list_diff([]), do: nil
def format_list_diff(:same), do: nil
def format_list_diff(list) do
{lines_a, lines_b} = Enum.unzip(list)
compare_view(
Enum.map(lines_a, &to_string/1),
Enum.map(lines_b, &to_string/1),
:center
)
end
def format_table_content_diff([]), do: nil
def format_table_content_diff(list) do
Stream.map(
list,
fn %{
table: table,
content_diff: content_diff,
index_diff: index_diff,
index_content_diff: index_content_diff
} ->
index_diff_lines =
case index_diff do
:same -> nil
%{index_diff: index_diff} -> format_list_diff(index_diff)
end
index_content_diff_lines =
case index_content_diff do
:same ->
[]
[] ->
[]
_ ->
Enum.map(index_content_diff, &format_index_content/1) |> Enum.intersperse("\n")
end
[
"\n#{IO.ANSI.blue()}Table name: #{table}#{IO.ANSI.reset()}\n",
format_table_content(content_diff),
index_diff_lines | index_content_diff_lines
]
|> Stream.reject(&is_nil/1)
|> Enum.intersperse("\n")
end
)
|> Stream.reject(&is_nil/1)
|> Enum.intersperse("\n")
end
def format_table_content(:same), do: "#{IO.ANSI.green()}Fields: same#{IO.ANSI.reset()}"
def format_table_content({table_a, table_b}) do
compare_view(
format_table(table_a),
format_table(table_b),
:left,
60
)
end
def format_table(table) do
table
|> inspect(pretty: true, limit: :infinity, width: 58)
|> String.split("\n")
end
def format_index_content(:same), do: "#{IO.ANSI.green()}Indexes: same#{IO.ANSI.reset()}"
def format_index_content(%{index: index, content_diff: {index_a, index_b}}) do
[
"\n#{IO.ANSI.blue()}Index name: #{index}#{IO.ANSI.reset()}\n\n",
compare_view(
format_table_index(index_a),
format_table_index(index_b),
:left,
60
)
]
end
def format_table_index(table_index) do
table_index
|> inspect(pretty: true, limit: :infinity, width: 58)
|> String.split("\n")
end
defp compare_view(lines_a, lines_b, align) do
max =
max(
Enum.max_by(lines_a, &String.length/1, fn -> 0 end) |> String.length(),
Enum.max_by(lines_a, &String.length/1, fn -> 0 end) |> String.length()
)
compare_view(lines_a, lines_b, align, max)
end
defp compare_view(lines_a, lines_b, align, max) do
len_a = length(lines_a)
len_b = length(lines_b)
max_len = max(len_a, len_b)
Enum.zip_with(
lines_a ++ List.duplicate("", max_len - len_a),
lines_b ++ List.duplicate("", max_len - len_b),
fn
left, left ->
content = padding_space(left, max, align)
[content, " | ", content]
left, right ->
[
IO.ANSI.red(),
padding_space(left, max, align),
" | ",
padding_space(right, max, align),
IO.ANSI.reset()
]
end
)
|> Enum.intersperse("\n")
end
defp padding_space(content, max, :left) do
String.pad_trailing(content, max)
end
defp padding_space(content, max, :center) do
len = String.length(content)
left_spaces = div(max - len, 2) + div(len, 2)
String.pad_leading(content, left_spaces)
|> String.pad_trailing(max)
end
defp padding_space(content, max, :right) do
String.pad_leading(content, max)
end
end