aboutsummaryrefslogtreecommitdiff
path: root/learn-you-some-erlang/mafiapp-1.0.0/src
diff options
context:
space:
mode:
Diffstat (limited to 'learn-you-some-erlang/mafiapp-1.0.0/src')
-rw-r--r--learn-you-some-erlang/mafiapp-1.0.0/src/mafiapp.erl172
-rw-r--r--learn-you-some-erlang/mafiapp-1.0.0/src/mafiapp_sup.erl12
2 files changed, 184 insertions, 0 deletions
diff --git a/learn-you-some-erlang/mafiapp-1.0.0/src/mafiapp.erl b/learn-you-some-erlang/mafiapp-1.0.0/src/mafiapp.erl
new file mode 100644
index 0000000..0e6a2b0
--- /dev/null
+++ b/learn-you-some-erlang/mafiapp-1.0.0/src/mafiapp.erl
@@ -0,0 +1,172 @@
+-module(mafiapp).
+-behaviour(application).
+-include_lib("stdlib/include/ms_transform.hrl").
+-export([start/2, stop/1]).
+-export([install/1]).
+-export([add_friend/4, friend_by_name/1, friend_by_expertise/1,
+ add_service/4, debts/1]).
+-export([add_enemy/2, find_enemy/1, enemy_killed/1]).
+
+
+-record(mafiapp_friends, {name,
+ contact=[],
+ info=[],
+ expertise}).
+-record(mafiapp_services, {from,
+ to,
+ date,
+ description}).
+-record(mafiapp_enemies, {name,
+ info=[]}).
+
+start(normal, []) ->
+ mnesia:wait_for_tables([mafiapp_friends,
+ mafiapp_services,
+ mafiapp_enemies], 5000),
+ mafiapp_sup:start_link().
+
+
+stop(_) -> ok.
+
+install(Nodes) ->
+ ok = mnesia:create_schema(Nodes),
+ rpc:multicall(Nodes, application, start, [mnesia]),
+ mnesia:create_table(mafiapp_friends,
+ [{attributes, record_info(fields, mafiapp_friends)},
+ {index, [#mafiapp_friends.expertise]},
+ {disc_copies, Nodes}]),
+ mnesia:create_table(mafiapp_services,
+ [{attributes, record_info(fields, mafiapp_services)},
+ {index, [#mafiapp_services.to]},
+ {disc_copies, Nodes},
+ {type, bag}]),
+ mnesia:create_table(mafiapp_enemies,
+ [{attributes, record_info(fields, mafiapp_enemies)},
+ {disc_copies, Nodes},
+ {local_content, true}]),
+ rpc:multicall(Nodes, application, stop, [mnesia]).
+
+add_friend(Name, Contact, Info, Expertise) ->
+ F = fun() ->
+ mnesia:write(#mafiapp_friends{name=Name,
+ contact=Contact,
+ info=Info,
+ expertise=Expertise})
+ end,
+ mnesia:activity(transaction, F).
+
+friend_by_name(Name) ->
+ F = fun() ->
+ case mnesia:read({mafiapp_friends, Name}) of
+ [#mafiapp_friends{contact=C, info=I, expertise=E}] ->
+ {Name,C,I,E,find_services(Name)};
+ [] ->
+ undefined
+ end
+ end,
+ mnesia:activity(transaction, F).
+
+friend_by_expertise(Expertise) ->
+ %% Alternative form:
+ %% MatchSpec = [{#mafiapp_friends{name = '$1',
+ %% contact = '$2',
+ %% info = '$3',
+ %% expertise = Expertise},
+ %% [],
+ %% [{{'$1','$2','$3',Expertise}}]}],
+ %% F = fun() ->
+ %% [{Name,C,I,E,find_services(Name)} ||
+ %% {Name,C,I,E} <- mnesia:select(mafiapp_friends, MatchSpec)]
+ %% end,
+ Pattern = #mafiapp_friends{_ = '_',
+ expertise = Expertise},
+ F = fun() ->
+ Res = mnesia:match_object(Pattern),
+ [{Name,C,I,Expertise,find_services(Name)} ||
+ #mafiapp_friends{name=Name,
+ contact=C,
+ info=I} <- Res]
+ end,
+ mnesia:activity(transaction, F).
+
+%% Adding validation is left to the reader
+add_service(From, To, Date, Description) ->
+ F = fun() ->
+ case mnesia:read({mafiapp_friends, From}) =:= [] orelse
+ mnesia:read({mafiapp_friends, To}) =:= [] of
+ true ->
+ {error, unknown_friend};
+ false ->
+ mnesia:write(#mafiapp_services{from=From,
+ to=To,
+ date=Date,
+ description=Description})
+ end
+ end,
+ mnesia:activity(transaction,F).
+
+debts(Name) ->
+ Match = ets:fun2ms(
+ fun(#mafiapp_services{from=From, to=To}) when From =:= Name ->
+ {To,-1};
+ (#mafiapp_services{from=From, to=To}) when To =:= Name ->
+ {From,1}
+ end),
+ F = fun() -> mnesia:select(mafiapp_services, Match) end,
+ Dict = lists:foldl(fun({Person,N}, Dict) ->
+ dict:update(Person, fun(X) -> X + N end, N, Dict)
+ end,
+ dict:new(),
+ mnesia:activity(transaction, F)),
+ lists:sort([{V,K} || {K,V} <- dict:to_list(Dict)]).
+%% The following implementation is a somewhat more efficient
+%% alternative on large databases, given it will use indexes
+%% rather than traversing the entire table.
+% F = fun() ->
+% Given = mnesia:read({mafiapp_services, Name}),
+% Received = mnesia:match_object(#mafiapp_services{to=Name, _='_'}),
+% {Given, Received}
+% end,
+% {Given, Received} = mnesia:activity(transaction, F),
+% Dict1 = lists:foldl(fun(#mafiapp_services{to=N}, Dict) ->
+% dict:update(N, fun(X) -> X - 1 end, -1, Dict)
+% end,
+% dict:new(),
+% Given),
+% Dict2 = lists:foldl(fun(#mafiapp_services{from=N}, Dict) ->
+% dict:update(N, fun(X) -> X + 1 end, 1, Dict)
+% end,
+% Dict1,
+% Received),
+% lists:sort([{V,K} || {K,V} <- dict:to_list(Dict2)]).
+
+add_enemy(Name, Info) ->
+ F = fun() -> mnesia:write(#mafiapp_enemies{name=Name, info=Info}) end,
+ mnesia:activity(transaction, F).
+
+find_enemy(Name) ->
+ F = fun() -> mnesia:read({mafiapp_enemies, Name}) end,
+ case mnesia:activity(transaction, F) of
+ [] -> undefined;
+ [#mafiapp_enemies{name=N, info=I}] -> {N,I}
+ end.
+
+enemy_killed(Name) ->
+ F = fun() -> mnesia:delete({mafiapp_enemies, Name}) end,
+ mnesia:activity(transaction, F).
+
+%%%%%%%%%%%%%%%
+%%% PRIVATE %%%
+%%%%%%%%%%%%%%%
+
+find_services(Name) ->
+ Match = ets:fun2ms(
+ fun(#mafiapp_services{from=From, to=To, date=D, description=Desc})
+ when From =:= Name ->
+ {to, To, D, Desc};
+ (#mafiapp_services{from=From, to=To, date=D, description=Desc})
+ when To =:= Name ->
+ {from, From, D, Desc}
+ end
+ ),
+ mnesia:select(mafiapp_services, Match).
diff --git a/learn-you-some-erlang/mafiapp-1.0.0/src/mafiapp_sup.erl b/learn-you-some-erlang/mafiapp-1.0.0/src/mafiapp_sup.erl
new file mode 100644
index 0000000..e31b221
--- /dev/null
+++ b/learn-you-some-erlang/mafiapp-1.0.0/src/mafiapp_sup.erl
@@ -0,0 +1,12 @@
+-module(mafiapp_sup).
+-behaviour(supervisor).
+-export([start_link/0]).
+-export([init/1]).
+
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+%% This does absolutely nothing, only there to
+%% allow to wait for tables.
+init([]) ->
+ {ok, {{one_for_one, 1, 1}, []}}.