Created
October 1, 2012 11:55
-
-
Save ToJans/3811189 to your computer and use it in GitHub Desktop.
Attempt for CQRS in erlang
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
%% INFRASTRUCTURE CRAP | |
load(Events) -> | |
load(#state{},Events). | |
load(State,[]) -> | |
State; | |
load(State,[Event|RemainingEvents]) -> | |
NewState = change(State,Event), | |
load(NewState,RemainingEvents). | |
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
-module(item). | |
-exports([handle/2]). | |
-define(TEST,1). | |
-include("item.hrl"). | |
%% COMMAND HANDLERS | |
handle(State,#activate_item{id=Id,name=Name}) -> | |
case State#state.active of | |
false -> | |
{ok, [#item_activated{id=Id,name=Name}]}; | |
true -> | |
{error, "you can not activate an item if it is already active"} | |
end; | |
handle(State,#deactivate_item{id=_Id}) when State#state.balance>0 -> | |
{error,"You can not deactivate this item as it is still in stock"}; | |
handle(State,#deactivate_item{id=Id}) -> | |
case State#state.active of | |
true -> | |
{ok, [#item_deactivated{id=Id}]}; | |
false -> | |
{error, "you can not deactivate an item if it is not active"} | |
end; | |
handle(State,_Command) when State#state.active == false -> | |
{error, "you can not perform any actions on an inactive item"}; | |
handle(_State,#deposit_amount{id=Id,amount=Amount}) -> | |
{ok, [#amount_deposited{id=Id,amount=Amount}]}; | |
handle(State,#withdraw_amount{id=_Id,amount=Amount}) when State#state.balance < Amount -> | |
{error, "the amount you want to withdraw is larger then the balance"}; | |
handle(_State,#withdraw_amount{id=Id,amount=Amount}) -> | |
{ok, [#amount_withdrawn{id=Id,amount=Amount}]}. | |
%% EVENT HANDLERS | |
change(State,#item_activated{id=_Id}) -> | |
State#state{active=true}; | |
change(State,#item_deactivated{id=_Id}) -> | |
State#state{active=false}; | |
change(State,#amount_deposited{id=_Id,amount=Amount}) -> | |
State#state{balance=State#state.balance+Amount}; | |
change(State,#amount_withdrawn{id=_Id,amount=Amount}) -> | |
State#state{balance=State#state.balance-Amount}. | |
-ifdef(TEST). | |
-include_lib("eunit/include/eunit.hrl"). | |
-include("infrastructure.erl"). | |
item_activation_test_() -> | |
[ | |
{"Activating for the first time should work", fun()-> | |
State = load([]), | |
Result = handle(State,#activate_item{id="item/1",name="Test item"}), | |
?assertEqual(Result,{ok,[#item_activated{id="item/1",name="Test item"}]}) | |
end }, | |
{"Activating twice in a row should fail", fun()-> | |
State = load([#item_activated{id="item/1",name="blah"}]), | |
{Status,_Message} = handle(State,#activate_item{id="item/1",name="Test item"}), | |
?assertEqual(Status,error) | |
end } | |
]. | |
item_deactivation_test_() -> | |
[ | |
{"Deactivating before activating should fail", fun()-> | |
State = load([]), | |
{Status,_Message} = handle(State,#deactivate_item{id="item/1"}), | |
?assertEqual(Status,error) | |
end }, | |
{"Deactivating after activating should work", fun()-> | |
State = load([#item_activated{id="item/1"}]), | |
Result = handle(State,#deactivate_item{id="item/1"}), | |
?assertEqual(Result,{ok,[#item_deactivated{id="item/1"}]}) | |
end }, | |
{"Deactivating a deactivated item should fail", fun()-> | |
State = load([#item_activated{id="item/1",name="blah"},#item_deactivated{id="item/1"}]), | |
{Status,_Message} = handle(State,#deactivate_item{id="item/1"}), | |
?assertEqual(Status,error) | |
end }, | |
{"Deactivating an active item with a balance should fail",fun() -> | |
State = load([#item_activated{id="item/1",name="blah"},#amount_deposited{id="item/1",amount=100}]), | |
{Status,_Message} = handle(State,#deactivate_item{id="item/1"}), | |
?assertEqual(Status,error) | |
end } | |
]. | |
deposit_amount_test_() -> | |
[ | |
{"Depositing an amount to an unactivated item should fail",fun()-> | |
State = load([]), | |
{Status,_Message} = handle(State,#deposit_amount{id="item/1"}), | |
?assertEqual(Status,error) | |
end}, | |
{"Depositing an amount to an activated item should succeed",fun()-> | |
State = load([#item_activated{id="item/1"}]), | |
Result = handle(State,#deposit_amount{id="item/1",amount=100}), | |
?assertEqual(Result,{ok,[#amount_deposited{id="item/1",amount=100}]}) | |
end} | |
]. | |
withdraw_amount_test_() -> | |
[ | |
{"Withdrawing an amount from an unactivated item should fail",fun()-> | |
State = load([]), | |
{Status,_Message} = handle(State,#withdraw_amount{id="item/1"}), | |
?assertEqual(Status,error) | |
end}, | |
{"Withdrawing an amount from an activated item with a balance large enough should succeed",fun()-> | |
State = load([#item_activated{id="item/1"},#amount_deposited{id="item/1",amount=200}]), | |
Result = handle(State,#withdraw_amount{id="item/1",amount=100}), | |
?assertEqual(Result,{ok,[#amount_withdrawn{id="item/1",amount=100}]}) | |
end}, | |
{"Withdrawing an amount for the second time where the total exceeds the balance should fail",fun()-> | |
State = load([#item_activated{id="item/1"},#amount_deposited{id="item/1",amount=120},#amount_withdrawn{id="item/1",amount=100}]), | |
{Status,_Message} = handle(State,#withdraw_amount{id="item/1",amount=100}), | |
?assertEqual(Status,error) | |
end } | |
]. | |
-endif. |
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
%% TYPE DECLARATIONS | |
-type item_id() :: nonempty_string(). | |
%% INTERNAL STATE RECORD | |
-record(state,{ id::item_id(), active=false :: boolean(),balance=0::non_neg_integer()}). | |
%% COMMANDS | |
-record(activate_item, {id::item_id(),name::nonempty_string()}). | |
-record(deactivate_item, {id::item_id()}). | |
-record(deposit_amount,{id::item_id(),amount=1::pos_integer()}). | |
-record(withdraw_amount,{id::item_id(),amount=1::pos_integer()}). | |
%% EVENTS | |
-record(item_activated, {id::item_id(),name::nonempty_string()}). | |
-record(item_deactivated, {id::item_id()}). | |
-record(amount_deposited,{id::item_id(),amount=1::pos_integer()}). | |
-record(amount_withdrawn,{id::item_id(),amount=1::pos_integer()}). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment