Skip to content

Instantly share code, notes, and snippets.

@krainboltgreene
Last active January 1, 2020 23:49
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save krainboltgreene/8dd468741864715bbe2c6f1be70b63e1 to your computer and use it in GitHub Desktop.
defmodule Amodel do
use Ecto.Schema
import Estate, only: [machine: 1]
machine([
onboarding_state: [
complete: [converted: "completed"]
],
role_state: [
grant_moderation_powers: [user: "moderator"],
grant_administrator_powers: [user: "administrator", moderator: "administrator"]
]
])
end
defmodule Estate do
defmacro machine(machines) do
Enum.flat_map(machines, fn ({column_name, events}) ->
Enum.flat_map(events, fn ({event_name, transitions}) ->
Enum.map(transitions, fn ({from, to}) ->
quote do
@desc "A before hook"
def unquote(:"before_#{event_name}")(%Ecto.Changeset{} = record) do
record
end
@desc "An after hook"
def unquote(:"after_#{event_name}")(%{} = record) do
record
end
@desc "An action to change the state, if the transition matches, but doesn't save"
def unquote(event_name)(%{unquote(column_name) => unquote(Atom.to_string(from))} = record) do
record
|> Ecto.Changeset.change()
|> unquote(:"before_#{event_name}")()
|> Ecto.Changeset.cast(%{unquote(column_name) => unquote(to)}, [unquote(column_name)])
|> Ecto.Changeset.validate_required(unquote(column_name))
|> unquote(:"after_#{event_name}")()
end
@desc "An action to change the state, if the transition matches, but does save"
def unquote(:"#{event_name}!")(%{:id => id, unquote(column_name) => unquote(Atom.to_string(from))} = record) when not is_nil(id) do
record
|> Ecto.Changeset.change()
|> unquote(:"before_#{event_name}")()
|> Ecto.Changeset.cast(%{unquote(column_name) => unquote(to)}, [unquote(column_name)])
|> Ecto.Changeset.validate_required(unquote(column_name))
|> Poutineer.Repo.update()
|> unquote(:"after_#{event_name}")()
end
# If you can't match, then raise transition failure
end
end)
end)
end)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment