Skip to content

Instantly share code, notes, and snippets.

@slashdotdash
Forked from Papipo/account.ex
Created November 17, 2016 20:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slashdotdash/5d502da954c0039b136a4e59d8200268 to your computer and use it in GitHub Desktop.
Save slashdotdash/5d502da954c0039b136a4e59d8200268 to your computer and use it in GitHub Desktop.
# Aggregates are just collections of command functions, which emit events,
# and event handlers, which mutate state.
# In order to hold state, they should be also structs.
# There is no new() function because aggregates aren't supposed to appear
# out of the blue, they are always the result of a command.
# In this case, %OpenAccount{}.
defmodule Bank.Account do
defstruct [:account_number, :balance]
# I like my commands and events to live in commands.ex and events.ex files
# on the root folder of my application.
# I think it's wonderful to have all that information at hand.
defmodule Commands do
import Commanded, only: [command: 2]
command OpenAccount, :account_number, [:initial_balance]
command Deposit, :account_number, [:amount]
command Withdraw, :account_number, [:amount]
end
defmodule Events do
import Commanded, only: [event: 1]
event AccountOpened, [:initial_balance]
event MoneyDeposited, [:amount]
event MoneyWithtrawn, [:amount]
end
alias Bank.Account
alias Account.Commands.{OpenAccount,Deposit,Withdraw}
alias Account.Events.{AccountOpened,MoneyDeposited,MoneyWidthrawn}
def execute(_, %OpenAccount{initial_balance: balance}) when balance < 0 do
raise "Initial balance can't be negative"
end
def execute(%Account{}, %OpenAccount{initial_balance: balance}) do
# We just return an event or a list of events
# The actor in charge of aggregates could just call List.wrap on whatever
# the aggregate returns.
%AccountOpened{initial_balance: initial_balance}
end
def apply(%Account{} = state, %AccountOpened = event) do
# Here we just return a new state
%Account{balance: event.initial_balance)
end
def execute(%Account{}, %Deposit{amount: amount} do
%MoneyDeposited{amount: amount}
end
def apply(%Account{balance: balance}, %MoneyDeposited{amount: amount}) do
%Account{balance: balance + amount}
end
def execute(%Account{balance: balance}, %MoneyWithdrawn{amount: amount}) when amount <= balance do
%Account{balance: balance - amount}
end
end
defmodule Commanded do
defmacro command(name, identifier_key, keys) do
quote do
defmodule unquote(name) do
defstruct [unquote(identifier_key) | unquote(keys)]
end
end
end
defmacro event(name, keys) do
quote do
defmodule unquote(name) do
defstruct unquote(keys)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment