Current section

Files

Jump to
excellent_migrations lib ast_parser_full_detections.ex
Raw

lib/ast_parser_full_detections.ex

defmodule ExcellentMigrations.AstParserFullDetections do
@moduledoc false
@index_functions [:create, :create_if_not_exists, :drop, :drop_if_exists]
@index_types [:index, :unique_index]
def parse(ast) do
full_ast_detections(ast)
end
defp full_ast_detections(ast) do
[
&detect_invalid_index_concurrently/1
]
|> Enum.map(&apply(&1, [ast]))
|> Enum.concat()
end
defp detect_invalid_index_concurrently(ast) do
default = %{
line: nil,
is_index_concurrently?: false,
ddl_transaction_disabled?: false,
lock_disabled?: false
}
ast
|> Macro.postwalk(default, &detect_invalid_index_concurrently_inner/2)
|> case do
{_, %{is_index_concurrently?: false}} ->
[]
{_, %{lock_disabled?: true, ddl_transaction_disabled?: true}} ->
[]
{_, %{lock_disabled?: true, ddl_transaction_disabled?: false, line: line}} ->
[{:index_concurrently_without_disable_ddl_transaction, line}]
{_, %{lock_disabled?: false, ddl_transaction_disabled?: true, line: line}} ->
[{:index_concurrently_without_disable_migration_lock, line}]
{_, %{line: line}} ->
[
{:index_concurrently_without_disable_migration_lock, line},
{:index_concurrently_without_disable_ddl_transaction, line}
]
end
end
defp detect_invalid_index_concurrently_inner(
{fun_name, location, [{operation, _, [_, _, options]}]} = ast_part,
acc
)
when fun_name in @index_functions and operation in @index_types do
is_concurrently? = Keyword.get(options, :concurrently, false) || acc.is_index_concurrently?
line = if is_concurrently?, do: Keyword.get(location, :line), else: acc.line
{ast_part, %{acc | is_index_concurrently?: is_concurrently?, line: line}}
end
defp detect_invalid_index_concurrently_inner(
{:disable_ddl_transaction, _, [true]} = ast_part,
acc
) do
{ast_part, %{acc | ddl_transaction_disabled?: true}}
end
defp detect_invalid_index_concurrently_inner(
{:disable_migration_lock, _, [true]} = ast_part,
acc
) do
{ast_part, %{acc | lock_disabled?: true}}
end
defp detect_invalid_index_concurrently_inner(ast_part, acc) do
{ast_part, acc}
end
end