Current section
Files
Jump to
Current section
Files
lib/ecto_enum_migration.ex
defmodule EctoEnumMigration do
@moduledoc """
Provides a DSL to easily handle Postgres Enum Types in Ecto database migrations.
"""
import Ecto.Migration, only: [execute: 1, execute: 2]
@doc """
Create a Postgres Enum Type.
## Examples
```elixir
defmodule MyApp.Repo.Migrations.CreateTypeMigration do
use Ecto.Migration
import EctoEnumMigration
def change do
create_type(:status, [:registered, :active, :inactive, :archived])
end
end
```
By default the type will be created in the `public` schema.
To change the schema of the type pass the `schema` option.
```elixir
create_type(:status, [:registered, :active, :inactive, :archived], schema: "custom_schema")
```
"""
@spec create_type(name :: atom(), values :: [atom()], opts :: Keyword.t()) :: :ok | no_return()
def create_type(name, values, opts \\ [])
when is_atom(name) and is_list(values) and is_list(opts) do
type_name = type_name(name, opts)
type_values = values |> Enum.map(fn value -> "'#{value}'" end) |> Enum.join(", ")
create_sql = "CREATE TYPE #{type_name} AS ENUM (#{type_values});"
drop_sql = "DROP TYPE #{type_name};"
execute(create_sql, drop_sql)
end
@doc """
Drop a Postgres Enum Type.
This command is not reversible, so make sure to include a `down/0` step in the migration.
## Examples
```elixir
defmodule MyApp.Repo.Migrations.DropTypeMigration do
use Ecto.Migration
import EctoEnumMigration
def up do
drop_type(:status)
end
def down do
create_type(:status, [:registered, :active, :inactive, :archived])
end
end
```
By default the type will be created in the `public` schema.
To change the schema of the type pass the `schema` option.
```elixir
drop_type(:status, schema: "custom_schema")
```
"""
@spec drop_type(name :: atom(), opts :: Keyword.t()) :: :ok | no_return()
def drop_type(name, opts \\ []) when is_atom(name) and is_list(opts) do
type_name = type_name(name, opts)
drop_sql = "DROP TYPE #{type_name};"
execute(drop_sql)
end
@doc """
Rename a Postgres Type.
## Examples
```elixir
defmodule MyApp.Repo.Migrations.RenameTypeMigration do
use Ecto.Migration
import EctoEnumMigration
def change do
rename_type(:status, :status_renamed)
end
end
```
By default the type will be created in the `public` schema.
To change the schema of the type pass the `schema` option.
```elixir
rename_type(:status, :status_renamed, schema: "custom_schema")
```
"""
@spec rename_type(before_name :: atom(), after_name :: atom(), opts :: Keyword.t()) ::
:ok | no_return()
def rename_type(before_name, after_name, opts \\ [])
when is_atom(before_name) and is_atom(after_name) and is_list(opts) do
before_type_name = type_name(before_name, opts)
after_type_name = type_name(after_name, opts)
up_sql = "ALTER TYPE #{before_type_name} RENAME TO #{after_name};"
down_sql = "ALTER TYPE #{after_type_name} RENAME TO #{before_name};"
execute(up_sql, down_sql)
end
defp type_name(name, opts) do
schema = Keyword.get(opts, :schema, "public")
"#{schema}.#{name}"
end
end