Last active
August 29, 2015 14:17
-
-
Save ddamko/c8cfa6a082a75a2b219b to your computer and use it in GitHub Desktop.
Elixir Playground
This file contains hidden or 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 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