use Vtc.Ecto.Postgres.Utils
defpgmodule Vtc.Ecto.Postgres.PgRational.Migrations do
@moduledoc """
Migrations for adding rational types, functions and constraints to a
Postgres database.
"""
alias Ecto.Migration
require Ecto.Migration
@doc section: :migrations_full
@doc """
Adds raw SQL queries to a migration for creating the database types, associated
functions, casts, operators, and operator families.
Safe to run multiple times when new functionality is added in updates to this library.
Existing values will be skipped.
## Types Created
Calling this macro creates the following type definitions:
```sql
CREATE TYPE public.rational AS (
numerator bigint,
denominator bigint
);
## Examples
```elixir
defmodule MyMigration do
use Ecto.Migration
alias Vtc.Ecto.Postgres.PgRational
require PgRational.Migrations
def change do
PgRational.Migrations.create_all()
end
end
```
"""
@spec create_all() :: :ok
def create_all do
:ok = create_type()
:ok
end
@doc section: :migrations_types
@doc """
Adds `rational` composite type.
"""
@spec create_type() :: :ok
def create_type do
:ok =
Migration.execute("""
DO $$ BEGIN
CREATE TYPE rational AS (
numerator bigint,
denominator bigint
);
EXCEPTION WHEN duplicate_object
THEN null;
END $$;
""")
:ok
end
@doc section: :migrations_constraints
@doc """
Creates basic constraints for a `PgRational` database field.
## Constraints created:
- `{field_name}_denominator_positive`: Checks that the denominator of the field is
positive.
## Examples
```elixir
create table("rationals", primary_key: false) do
add(:id, :uuid, primary_key: true, null: false)
add(:a, PgRational.type())
add(:b, PgRational.type())
end
PgRational.migration_add_field_constraints(:rationals, :a)
PgRational.migration_add_field_constraints(:rationals, :b)
```
"""
@spec create_field_constraints(atom(), atom()) :: :ok
def create_field_constraints(table, field_name) do
Migration.create(
Migration.constraint(
table,
"#{field_name}_denominator_positive",
check: """
(#{field_name}).denominator > 0
"""
)
)
:ok
end
end