Skip to content

Instantly share code, notes, and snippets.

@ddamko
Last active August 29, 2015 14:17
Show Gist options
  • Save ddamko/c8cfa6a082a75a2b219b to your computer and use it in GitHub Desktop.
Save ddamko/c8cfa6a082a75a2b219b to your computer and use it in GitHub Desktop.
Elixir Playground
defmodule BankPlayground do
defmodule State do
defstruct [:id, :date_created, :balance, :changes]
@type t :: %State{}
end
defmodule AccountCreated do
defstruct [:id, :date_created]
@type t :: %AccountCreated{}
end
defmodule MoneyDeposited do
defstruct [:id, :amount, :new_balance, :transaction_date]
@type t :: %MoneyDeposited{}
end
defmodule MoneyWithdrawn do
defstruct [:id, :amount, :new_balance, :transaction_date]
@type t :: %MoneyWithdrawn{}
end
defmodule PaymentDeclined do
defstruct [:id, :amount, :transaction_date]
@type t :: %PaymentDeclined{}
end
alias BankPlayground.State
alias BankPlayground.AccountCreated
alias BankPlayground.MoneyDeposited
alias BankPlayground.MoneyWithdrawn
alias BankPlayground.PaymentDeclined
def new() do
spawn fn -> init() end
end
def create(pid, id) do
send pid, {:attempt_command, {:create, id}}
end
def deposit(pid, amount) do
send pid, {:attempt_command, {:deposit_money, amount}}
end
def withdraw(pid, amount) do
send pid, {:attempt_command, {:withdraw_money, amount}}
end
def init() do
state = %{%State{} | :balance => 0}
loop(state)
end
def loop(state) do
receive do
{:apply_event, event} ->
new_state = apply_event(event, state)
loop(new_state)
{:attempt_command, command} ->
new_state = attempt_command(command, state)
IO.inspect(new_state)
loop(new_state)
end
end
def attempt_command({:create, id}, state) do
event = %{%AccountCreated{} | :id => id, :date_created => :calendar.local_time}
apply_new_event(event, state)
end
def attempt_command({:deposit_money, amount}, state) do
new_balance = Map.update(state, :balance, 0, &(&1 + amount))
id = Map.get(state, :id)
event = %{%MoneyDeposited{} | :id => id, :amount => amount, :new_balance => new_balance.balance, :transaction_date => :calendar.local_time}
apply_new_event(event, state)
end
def attempt_command({:withdraw_money, amount}, state) do
new_balance = Map.update(state, :balance, 0, &(&1 - amount))
id = Map.get(state, :id)
event = case Map.get(new_balance, :balance) < 0 do
false ->
%{%MoneyWithdrawn{} | :id => id, :amount => amount, :new_balance => new_balance.balance, :transaction_date => :calendar.local_time}
true ->
%{%PaymentDeclined{} | :id => id, :amount => amount, :transaction_date => :calendar.local_time}
end
apply_new_event(event, state)
end
def apply_new_event(event, state) do
new_state = apply_event(event, state)
Map.update(new_state, :changes, [], &[event|&1])
end
def apply_event(event = %BankPlayground.AccountCreated{}, state) do
id = Map.get(event, :id)
date = Map.get(event, :date_created)
%{state | :id => id, :date_created => date}
end
def apply_event(event = %BankPlayground.MoneyDeposited{}, state) do
amount = Map.get(event, :amount)
balance = Map.get(state, :balance)
new_balance = balance + amount
%{state | :balance => new_balance}
end
def apply_event(event = %BankPlayground.MoneyWithdrawn{}, state) do
amount = Map.get(event, :amount)
balance = Map.get(state, :balance)
new_balance = balance - amount
%{state | :balance => new_balance}
end
def apply_event(event = %BankPlayground.PaymentDeclined{}, state) do
IO.puts "Sorry you do not have enough money."
IO.inspect(event)
state
end
end
# %BankPlayground.State{
# balance: 331,
# changes: [
# %BankPlayground.MoneyWithdrawn{amount: 67, id: 35, new_balance: 331, transaction_date: {{2015, 3, 19}, {13, 7, 36}}},
# %BankPlayground.MoneyWithdrawn{amount: 45, id: 35, new_balance: 398, transaction_date: {{2015, 3, 19}, {13, 7, 30}}},
# %BankPlayground.MoneyWithdrawn{amount: 23, id: 35, new_balance: 443, transaction_date: {{2015, 3, 19}, {13, 7, 23}}},
# %BankPlayground.MoneyDeposited{amount: 78, id: 35, new_balance: 466, transaction_date: {{2015, 3, 19}, {13, 7, 11}}},
# %BankPlayground.MoneyDeposited{amount: 54, id: 35, new_balance: 388, transaction_date: {{2015, 3, 19}, {13, 7, 5}}},
# %BankPlayground.MoneyDeposited{amount: 234, id: 35, new_balance: 334, transaction_date: {{2015, 3, 19}, {13, 6, 59}}},
# %BankPlayground.MoneyDeposited{amount: 100, id: 35, new_balance: 100, transaction_date: {{2015, 3, 19}, {13, 6, 28}}},
# %BankPlayground.AccountCreated{date_created: {{2015, 3, 19}, {13, 5, 27}}, id: 35} | nil],
# date_created: {{2015, 3, 19}, {13, 5, 27}},
# id: 35}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment