Packages

ash_postgres

0.34.2
2.10.0 2.9.1 2.9.0 2.8.0 2.7.0 2.6.32 2.6.31 2.6.30 2.6.29 2.6.28 2.6.27 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.22 2.5.21 2.5.20 2.5.19 2.5.18 2.5.17 2.5.16 2.5.15 2.5.14 2.5.13 2.5.12 2.5.11 2.5.10 2.5.9 2.5.8 2.5.7 2.5.6 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.4.21 2.4.20 2.4.19 2.4.18 2.4.17 2.4.16 2.4.15 2.4.14 2.4.13 2.4.12 2.4.11 2.4.10 2.4.9 2.4.8 2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 2.3.1 2.3.0 2.2.5 2.2.4 2.2.3 2.2.2 2.2.1 2.2.0 2.1.19 2.1.18 2.1.17 2.1.15 2.1.14 2.1.13 2.1.12 2.1.11 2.1.10 2.1.9 2.1.8 2.1.6 2.1.5 2.1.4 2.1.3 2.1.2 2.1.1 2.1.0 2.0.12 2.0.11 2.0.10 2.0.9 2.0.8 2.0.7 2.0.6 2.0.5 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 2.0.0-rc.15 2.0.0-rc.14 2.0.0-rc.13 2.0.0-rc.12 2.0.0-rc.11 2.0.0-rc.10 2.0.0-rc.9 2.0.0-rc.8 2.0.0-rc.7 2.0.0-rc.6 2.0.0-rc.5 2.0.0-rc.4 2.0.0-rc.3 2.0.0-rc.2 2.0.0-rc.1 2.0.0-rc.0 1.5.30 1.5.29 1.5.28 1.5.27 1.5.26 1.5.25 1.5.24 1.5.23 1.5.22 1.5.21 1.5.20 1.5.19 1.5.18 1.5.17 1.5.16 1.5.15 1.5.14 1.5.13 1.5.12 1.5.11 1.5.10 1.5.9 1.5.8 1.5.7 1.5.6 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 1.4.0 1.3.68 1.3.67 1.3.66 1.3.65 1.3.64 1.3.63 1.3.62 1.3.61 1.3.60 1.3.59 1.3.58 1.3.56 1.3.55 1.3.54 1.3.53 1.3.52 1.3.51 1.3.50 1.3.49 1.3.48 1.3.47 1.3.46 1.3.45 1.3.44 1.3.43 1.3.42 1.3.41 1.3.40 1.3.39 1.3.38 1.3.37 1.3.36 1.3.35 1.3.34 1.3.33 1.3.32 1.3.31 1.3.30 1.3.29 1.3.28 1.3.26 1.3.25 1.3.24 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 1.3.18 1.3.17 1.3.16 1.3.15 1.3.14 1.3.12 1.3.11 1.3.10 1.3.9 1.3.8 1.3.6 1.3.5 1.3.4 1.3.3 1.3.2 1.3.1 1.3.0 1.3.0-rc.4 1.3.0-rc.3 1.3.0-rc.2 1.3.0-rc.0 1.2.6 1.2.5 1.2.4 1.2.3 1.2.2 1.2.1 1.2.0 1.2.0-rc.1 1.2.0-rc.0 1.1.3 1.1.2 1.1.1 1.1.0 1.0.0 1.0.0-rc.9 1.0.0-rc.8 1.0.0-rc.7 1.0.0-rc.6 1.0.0-rc.5 1.0.0-rc.4 1.0.0-rc.3 1.0.0-rc.2 1.0.0-rc.1 1.0.0-rc.0 1.0.0-pre.3 1.0.0-pre.2 1.0.0-pre.1 1.0.0-pre.0 0.43.0 0.42.0-rc.7 0.42.0-rc.6 0.42.0-rc.5 0.42.0-rc.4 0.42.0-rc.3 0.42.0-rc.1 0.42.0-rc.0 0.41.7 0.41.6 0.41.5 0.41.4 0.41.3 0.41.2 0.41.1 0.41.0-rc0 retired 0.41.0-rc.9 0.41.0-rc.8 0.41.0-rc.7 0.41.0-rc.6 0.41.0-rc.5 0.41.0-rc.4 0.41.0-rc.3 0.41.0-rc.2 0.41.0-rc.1 0.41.0-rc.0 0.40.11 0.40.10 0.40.9 0.40.8 0.40.7 0.40.6 0.40.5 0.40.4 0.40.3 0.40.2 0.40.1 0.40.0-rc5 0.40.0-rc4 0.40.0-rc3 0.40.0-rc2 0.40.0-rc1 0.39.0-rc0 0.38.11 0.38.10 0.38.9 0.38.8 0.38.7 0.38.6 0.38.5 0.38.4 0.38.3 0.38.2 0.38.1 0.38.0 0.37.8 0.37.7 0.37.6 0.37.5 0.37.4 0.37.3 0.37.2 0.37.1 0.37.0 0.36.5 0.36.4 0.36.3 0.36.2 0.36.1 0.36.0 0.35.5 0.35.4 0.35.3 0.35.1 0.34.5 0.34.4 0.34.3 0.34.2 0.34.1 0.34.0 0.33.1 0.33.0 0.32.2 0.32.1 0.32.0 0.31.1 0.30.1 0.29.6 0.29.5 0.29.4 0.29.3 0.29.2 0.29.1 0.28.1 0.28.0 0.27.0 0.26.2 0.26.1 0.26.0 0.25.5 0.25.4 0.25.3 0.25.2 0.25.1 0.25.0 0.24.0 0.23.2 0.23.1 0.23.0 0.22.1 0.22.0 0.21.0 0.20.1 0.20.0 0.19.0 0.18.0 0.17.0 0.16.1 0.15.0 0.14.0 0.13.0 0.12.1 0.12.0 0.11.2 0.10.0 0.9.0 0.8.0 0.7.0 0.6.0 0.5.0 0.4.0 0.3.0 0.2.1 0.2.0 0.1.4 0.1.3 0.1.2 0.1.1 0.1.1-rc.2 0.1.1-rc.1 0.1.1-rc.0 0.1.0

The PostgreSQL data layer for Ash Framework

Current section

Files

Jump to
ash_postgres lib migration_generator operation.ex
Raw

lib/migration_generator/operation.ex

defmodule AshPostgres.MigrationGenerator.Operation do
@moduledoc false
defmodule Helper do
@moduledoc false
def join(list),
do:
list
|> List.flatten()
|> Enum.reject(&is_nil/1)
|> Enum.join(", ")
|> String.replace(", )", ")")
def maybe_add_default("nil"), do: nil
def maybe_add_default(value), do: "default: #{value}"
def maybe_add_primary_key(true), do: "primary_key: true"
def maybe_add_primary_key(_), do: nil
def maybe_add_null(false), do: "null: false"
def maybe_add_null(_), do: nil
end
defmodule CreateTable do
@moduledoc false
defstruct [:table, :multitenancy, :old_multitenancy]
end
defmodule AddAttribute do
@moduledoc false
defstruct [:attribute, :table, :multitenancy, :old_multitenancy]
import Helper
def up(%{
multitenancy: %{strategy: :attribute, attribute: source_attribute},
attribute:
%{
references: %{
table: table,
destination_field: destination_field,
multitenancy: %{strategy: :attribute, attribute: destination_attribute}
}
} = attribute
}) do
[
"add #{inspect(attribute.name)}",
"references(:#{table}",
[
"type: #{inspect(attribute.type)}",
"column: #{inspect(destination_field)}",
"with: [#{source_attribute}: :#{destination_attribute}]"
],
")",
maybe_add_default(attribute.default),
maybe_add_primary_key(attribute.primary_key?)
]
|> join()
end
def up(%{
multitenancy: %{strategy: :context},
attribute:
%{
references: %{
table: table,
destination_field: destination_field,
multitenancy: %{strategy: :attribute}
}
} = attribute
}) do
[
"add #{inspect(attribute.name)}",
"references(:#{table}",
[
"type: #{inspect(attribute.type)}",
"column: #{inspect(destination_field)}",
"name: \"\#\{prefix()\}_#{table}_#{attribute.name}_fkey\"",
"prefix: \"public\""
],
")",
maybe_add_default(attribute.default),
maybe_add_primary_key(attribute.primary_key?)
]
|> join()
end
def up(%{
multitenancy: %{strategy: :attribute},
table: current_table,
attribute:
%{
references: %{
table: table,
multitenancy: %{strategy: :context}
}
} = attribute
}) do
Mix.shell().info("""
table `#{current_table}` with attribute multitenancy refers to table `#{table}` with schema based multitenancy.
This means that it is not possible to use a foreign key. This is not necessarily a problem, just something
you should be aware of
""")
[
"add #{inspect(attribute.name)}",
inspect(attribute.type),
maybe_add_default(attribute.default),
maybe_add_primary_key(attribute.primary_key?)
]
|> join()
end
def up(%{
multitenancy: %{strategy: :context},
attribute:
%{references: %{table: table, destination_field: destination_field}} = attribute
}) do
[
"add #{inspect(attribute.name)}",
"references(:#{table}",
[
"type: #{inspect(attribute.type)}",
"column: #{inspect(destination_field)}",
"name: \"\#\{prefix()\}_#{table}_#{attribute.name}_fkey\""
],
")",
maybe_add_default(attribute.default),
maybe_add_primary_key(attribute.primary_key?)
]
|> join()
end
def up(%{
attribute:
%{references: %{table: table, destination_field: destination_field}} = attribute
}) do
[
"add #{inspect(attribute.name)}",
"references(:#{table}",
[
"type: #{inspect(attribute.type)}",
"column: #{inspect(destination_field)}"
],
")",
maybe_add_default(attribute.default),
maybe_add_primary_key(attribute.primary_key?)
]
|> join()
end
def up(%{attribute: %{type: :integer, default: "nil", generated?: true} = attribute}) do
[
"add #{inspect(attribute.name)}",
":serial",
maybe_add_null(attribute.allow_nil?),
maybe_add_primary_key(attribute.primary_key?)
]
|> join()
end
def up(%{attribute: attribute}) do
[
"add #{inspect(attribute.name)}",
"#{inspect(attribute.type)}",
maybe_add_null(attribute.allow_nil?),
maybe_add_default(attribute.default),
maybe_add_primary_key(attribute.primary_key?)
]
|> join()
end
def down(
%{
attribute: attribute,
table: table,
multitenancy: multitenancy
} = op
) do
AshPostgres.MigrationGenerator.Operation.RemoveAttribute.up(%{
op
| attribute: attribute,
table: table,
multitenancy: multitenancy
})
end
end
defmodule AlterAttribute do
@moduledoc false
defstruct [:old_attribute, :new_attribute, :table, :multitenancy, :old_multitenancy]
defp alter_opts(attribute, old_attribute) do
primary_key =
if attribute.primary_key? and !old_attribute.primary_key? do
", primary_key: true"
end
default =
if attribute.default != old_attribute.default do
if is_nil(attribute.default) do
", default: nil"
else
", default: #{attribute.default}"
end
end
null =
if attribute.allow_nil? != old_attribute.allow_nil? do
", null: #{attribute.allow_nil?}"
end
"#{null}#{default}#{primary_key}"
end
def up(%{
multitenancy: multitenancy,
old_attribute: old_attribute,
new_attribute: attribute
}) do
type_or_reference =
if AshPostgres.MigrationGenerator.has_reference?(multitenancy, attribute) and
Map.get(old_attribute, :references) != Map.get(attribute, :references) do
reference(multitenancy, attribute)
else
inspect(attribute.type)
end
"modify #{inspect(attribute.name)}, #{type_or_reference}#{
alter_opts(attribute, old_attribute)
}"
end
defp reference(%{strategy: :context}, %{
type: type,
name: name,
references: %{
multitenancy: %{strategy: :context},
table: table,
destination_field: destination_field
}
}) do
"references(:#{table}, type: #{inspect(type)}, column: #{inspect(destination_field)}, name: \"\#\{prefix()\}_#{
table
}_#{name}_fkey\")"
end
defp reference(%{strategy: :attribute, attribute: source_attribute}, %{
type: type,
references: %{
multitenancy: %{strategy: :attribute, attribute: destination_attribute},
table: table,
destination_field: destination_field
}
}) do
"references(:#{table}, type: #{inspect(type)}, column: #{inspect(destination_field)}, with: [#{
source_attribute
}: :#{destination_attribute}])"
end
defp reference(
%{strategy: :context},
%{
type: type,
references: %{
table: table,
destination_field: destination_field
}
}
) do
"references(:#{table}, type: #{inspect(type)}, column: #{inspect(destination_field)}, prefix(): \"public\")"
end
defp reference(
_,
%{
type: type,
references: %{
table: table,
destination_field: destination_field
}
}
) do
"references(:#{table}, type: #{inspect(type)}, column: #{inspect(destination_field)})"
end
def down(op) do
up(%{
op
| old_attribute: op.new_attribute,
new_attribute: op.old_attribute,
old_multitenancy: op.multitenancy,
multitenancy: op.old_multitenancy
})
end
end
defmodule DropForeignKey do
@moduledoc false
# We only run this migration in one direction, based on the input
# This is because the creation of a foreign key is handled by `references/3`
# We only need to drop it before altering an attribute with `references/3`
defstruct [:attribute, :table, :multitenancy, :direction, no_phase: true]
def up(%{attribute: attribute, table: table, multitenancy: multitenancy, direction: :up}) do
if multitenancy && multitenancy.strategy == :context do
"drop constraint(:#{table}, \"\#\{prefix()\}_#{table}_#{attribute.name}_fkey\")"
else
"drop constraint(:#{table}, \"#{table}_#{attribute.name}_fkey\")"
end
end
def up(_), do: ""
def down(%{attribute: attribute, table: table, multitenancy: multitenancy, direction: :down}) do
if multitenancy && multitenancy.strategy == :context do
"drop constraint(:#{table}, \"\#\{prefix()\}_#{table}_#{attribute.name}_fkey\")"
else
"drop constraint(:#{table}, \"#{table}_#{attribute.name}_fkey\")"
end
end
def down(_), do: ""
end
defmodule RenameAttribute do
@moduledoc false
defstruct [
:old_attribute,
:new_attribute,
:table,
:multitenancy,
:old_multitenancy,
no_phase: true
]
def up(%{old_attribute: old_attribute, new_attribute: new_attribute, table: table}) do
"rename table(:#{table}), #{inspect(old_attribute.name)}, to: #{inspect(new_attribute.name)}"
end
def down(%{new_attribute: old_attribute, old_attribute: new_attribute, table: table}) do
"rename table(:#{table}), #{inspect(old_attribute.name)}, to: #{inspect(new_attribute.name)}"
end
end
defmodule RemoveAttribute do
@moduledoc false
defstruct [:attribute, :table, :multitenancy, :old_multitenancy, commented?: true]
def up(%{attribute: attribute, commented?: true}) do
"""
# Attribute removal has been commented out to avoid data loss. See the migration generator documentation for more
# If you uncomment this, be sure to also uncomment the corresponding attribute *addition* in the `down` migration
# remove #{inspect(attribute.name)}
"""
end
def up(%{attribute: attribute}) do
"remove #{inspect(attribute.name)}"
end
def down(%{attribute: attribute, multitenancy: multitenancy, commented?: true}) do
prefix = """
# This is the `down` migration of the statement:
#
# remove #{inspect(attribute.name)}
#
"""
contents =
%AshPostgres.MigrationGenerator.Operation.AddAttribute{
attribute: attribute,
multitenancy: multitenancy
}
|> AshPostgres.MigrationGenerator.Operation.AddAttribute.up()
|> String.split("\n")
|> Enum.map(&"# #{&1}")
|> Enum.join("\n")
prefix <> "\n" <> contents
end
def down(%{attribute: attribute, multitenancy: multitenancy}) do
AshPostgres.MigrationGenerator.Operation.AddAttribute.up(
%AshPostgres.MigrationGenerator.Operation.AddAttribute{
attribute: attribute,
multitenancy: multitenancy
}
)
end
end
defmodule AddUniqueIndex do
@moduledoc false
defstruct [:identity, :table, :multitenancy, :old_multitenancy, no_phase: true]
def up(%{
identity: %{name: name, keys: keys, base_filter: base_filter},
table: table,
multitenancy: multitenancy
}) do
{name_prefix, keys} =
case multitenancy.strategy do
:context ->
{"\#\{prefix()\}_", keys}
:attribute ->
{"", [multitenancy.attribute | keys]}
_ ->
{"", keys}
end
if base_filter do
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{
name_prefix
}#{table}_#{name}_unique_index\", where: \"#{base_filter}\")"
else
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{
name_prefix
}#{table}_#{name}_unique_index\")"
end
end
def down(%{
identity: %{name: name, keys: keys},
table: table,
multitenancy: multitenancy
}) do
{name_prefix, keys} =
case multitenancy.strategy do
:context ->
{"\#\{prefix()\}_", keys}
:attribute ->
{"", [multitenancy.attribute | keys]}
_ ->
{"", keys}
end
"drop_if_exists unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{
name_prefix
}#{table}_#{name}_unique_index\")"
end
end
defmodule RemoveUniqueIndex do
@moduledoc false
defstruct [:identity, :table, :multitenancy, :old_multitenancy, no_phase: true]
def up(%{identity: %{name: name, keys: keys}, table: table, old_multitenancy: multitenancy}) do
{name_prefix, keys} =
case multitenancy.strategy do
:context ->
{"\#\{prefix()\}_", keys}
:attribute ->
{"", [multitenancy.attribute | keys]}
_ ->
{"", keys}
end
"drop_if_exists unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{
name_prefix
}#{table}_#{name}_unique_index\")"
end
def down(%{
identity: %{name: name, keys: keys, base_filter: base_filter},
table: table,
multitenancy: multitenancy
}) do
{name_prefix, keys} =
case multitenancy.strategy do
:context ->
{"\#\{prefix()\}_", keys}
:attribute ->
{"", [multitenancy.attribute | keys]}
_ ->
{"", keys}
end
if base_filter do
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{
name_prefix
}#{table}_#{name}_unique_index\", where: \"#{base_filter}\")"
else
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{
name_prefix
}#{table}_#{name}_unique_index\")"
end
end
end
end