ex_workflow v0.1.0 ExWorkflow
A minimal workflow implementation for Ecto schemas. Inspired by Ruby's geekq/workflow.
Usage
By importing ExWorkflow
into your Ecto schema module,
you can define your workflow in the format of
workflow do
state ~> event ~> new_state
...
end
The default state field is state
.
If you want to use a custom field to store the states,
you can pass state_field: <custom state field name>
to the workflow
macro:
workflow state_field: :my_state do
...
end
Example
defmodule Article do
use Ecto.Schema
import ExWorkflow
import Ecto.Changeset
schema "articles" do
field :state, :string
end
workflow do
# state ~> event ~> new_state
"unpublished" ~> :publish ~> "published"
"published" ~> :unpublish ~> "unpublished"
"unpublished" ~> :trash ~> "trashed_unpublished"
"published" ~> :trash ~> "trashed_published"
"trashed_unpublished" ~> :recycle ~> "unpublished"
"trashed_published" ~> :recycle ~> "published"
end
# You can override the event :publish. It should return a changeset.
# The `super` keyword is also available.
def publish(changeset) do
# Do something interesting
super(changeset)
end
# You can also pass 1 additional argument of any type.
def publish(changeset, discard_draft: true) do
...
end
end
Each event gives 2 functions named after the event,
for example, the :publish
event, gives publish(changeset)
and publish(changeset, addtional_arg)
.
The additional argument is by default ignored, but you can override it.
changeset = %Article{}
|> Ecto.Changeset.cast(%Article{state: "unpublished"}, %{}, [:state])
|> Article.publish()
Ecto.Changeset.get_field(changeset, :state) #=> "published"
changeset = Article.trash(changeset)
Ecto.Changeset.get_field(changeset, :state) #=> "trashed_published"
changeset = Article.recycle(changeset)
Ecto.Changeset.get_field(changeset, :state) #=> "published"
TODO
- Workflow specification API
- Draw workflow diagram