defmodule Ecto.Adapters.Mnesia.Constraint do
@moduledoc """
Functions for checking records against constraints
"""
alias Ecto.Adapters.Mnesia.Constraint.Proto
alias Ecto.Adapters.Mnesia.Source
import Record
defrecord :mnesia_constraints, table: nil, constraint: nil
@table :mnesia_constraints
@type constraint() :: {:unique | :foreign_key | :exclusion | :check, String.t()}
@doc """
Check parameters against constraints.
Returns eventually violated constraints
"""
@spec check(Source.t(), Keyword.t()) :: [constraint()]
def check(source, params) do
source.table
|> get()
|> Enum.reduce([], fn mnesia_constraints(constraint: c), acc ->
case Proto.check(c, params) do
:ok -> acc
{:error, reason} -> [reason | acc]
end
end)
end
@doc """
Returns constraints for the given table
"""
def get(table) do
:mnesia.transaction(fn ->
:mnesia.read(@table, table, :read)
end)
|> case do
{:atomic, c} -> c
end
end
@doc """
Register a constraint
"""
def register(constraint) do
:mnesia.transaction(fn ->
:mnesia.write(mnesia_constraints(table: Proto.table(constraint), constraint: constraint))
end)
|> case do
{:atomic, c} -> c
end
end
@doc """
Ensure constraints table has been created
"""
def ensure_table(nodes) do
case :mnesia.create_table(@table,
disc_copies: nodes,
attributes: [:table, :constraint],
type: :bag,
storage_properties: [dets: [auto_save: 5_000]],
load_order: 100
) do
{:atomic, :ok} ->
:mnesia.wait_for_tables([@table], 1_000)
{:aborted, {:already_exists, @table}} ->
:mnesia.wait_for_tables([@table], 1_000)
end
end
end