Last active
September 14, 2017 10:35
-
-
Save slashdotdash/f2c4850a5879b483e92bc6bf2b1dd8af to your computer and use it in GitHub Desktop.
Example shopping cart aggregate using Chronik
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Example.Cart do | |
use Chronik.Aggregate | |
alias Example.Cart | |
alias Example.DomainEvents.{CartCreated, ItemsAdded, ItemsRemoved} | |
defstruct [id: nil, items: %{}] | |
## Public API | |
def create(id), do: Aggregate.command(id, {:create, id}) | |
def add_items(id, item_id, quantity), do: Aggregate.command(id, {:add_items, id, item_id, quantity}) | |
def remove_items(id, item_id, quantity), do: Aggregate.command(id, {:remove_items, id, item_id, quantity}) | |
## Cart commands | |
def handle_command({:create, id}, nil) do | |
%CartCreated{id: id} | |
end | |
def handle_command({:create, id}, _state) do | |
raise CartExistsError, "Cart already created" | |
end | |
def handle_command({:add_items, id, item_id, quantity}, %Cart{}) do | |
%ItemsAdded{id: id, item_id: item_id, quantity: quantity} | |
end | |
def handle_command({:remove_items, id, item_id, quantity}, %Cart{items: items}) do | |
current_quantity = (items[item_id] || 0) | |
if current_quantity >= quantity do | |
%ItemsRemoved{id: id, item_id: item_id, quantity: quantity} | |
else | |
raise CartEmptyError, "Cannot remove items from cart #{id}" | |
end | |
end | |
## State transitions | |
def handle_event(%CartCreated{id: id}, nil) do | |
%Cart{id: id} | |
end | |
def handle_event(%ItemsAdded{item_id: item_id, quantity: quantity}, state) do | |
current_quantity = (state.items[item_id] || 0) + quantity | |
%{state | items: Map.put(state.items, item_id, current_quantity)} | |
end | |
def handle_event(%ItemsRemoved{item_id: item_id, quantity: quantity}, state) do | |
current_quantity = (state.items[item_id] || 0) - quantity | |
%{state | items: Map.put(state.items, item_id, current_quantity)} | |
end | |
## | |
## Exceptions | |
## | |
defmodule CartExistsError do | |
defexception [:message] | |
end | |
defmodule CartEmptyError do | |
defexception [:message] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment