%%%------------------------------------------------------------------- %%% @author aresei %%% @copyright (C) 2023, %%% @doc %%% %%% @end %%% Created : 26. 7月 2023 10:40 %%%------------------------------------------------------------------- -module(mnesia_totalizator). -author("aresei"). -include("iot.hrl"). -include_lib("stdlib/include/qlc.hrl"). -define(TAB_NAME, totalizator). %% API -export([create_table/0]). -export([increment_success/2, increment_fail/2, delete/2, table_size/0, query/2]). create_table() -> %% id生成器 mnesia:create_table(?TAB_NAME, [ {attributes, record_info(fields, totalizator)}, {record_name, totalizator}, {disc_copies, [node()]}, {type, ordered_set} ]). -spec query(SceneIds :: [integer()], Dates :: [calendar:date()]) -> [map()]. query(SceneIds, Dates) when is_list(SceneIds), is_list(Dates) -> lists:map(fun(Date) -> Scenes = lists:map(fun(SceneId) -> Key = {SceneId, Date}, case mnesia:dirty_read(?TAB_NAME, Key) of [R | _] -> to_map(R); [] -> #{<<"scene_id">> => SceneId, <<"success_num">> => 0, <<"fail_num">> => 0} end end, SceneIds), #{<<"date">> => format_date(Date), <<"scenes">> => Scenes} end, Dates). -spec increment_success(SceneId :: integer(), IncNum :: integer()) -> ok | {error, Reason :: any()}. increment_success(SceneId, IncNum) when is_integer(SceneId), is_integer(IncNum) -> increment(SceneId, success, IncNum). -spec increment_fail(SceneId :: integer(), IncNum :: integer()) -> ok | {error, Reason :: any()}. increment_fail(SceneId, IncNum) when is_integer(SceneId), is_integer(IncNum) -> increment(SceneId, fail, IncNum). -spec increment(SceneId :: integer(), Type :: atom(), IncNum :: integer()) -> ok | {error, Reason :: any()}. increment(SceneId, Type, IncNum) when is_integer(SceneId), is_integer(IncNum), is_atom(Type) -> {Date, _} = calendar:local_time(), Key = {SceneId, Date}, Fun = fun() -> case mnesia:read(?TAB_NAME, Key) of [R = #totalizator{option = Option = #option{success_num = SuccessNum, fail_num = FailNum}} | _] -> NOption = case Type of success -> Option#option{success_num = SuccessNum + IncNum}; fail -> Option#option{fail_num = FailNum + IncNum} end, NR = R#totalizator{option = NOption}, mnesia:write(?TAB_NAME, NR, write); [] -> Option = case Type of success -> #option{success_num = IncNum}; fail -> #option{fail_num = IncNum} end, R = #totalizator{key = Key, scene_id = SceneId, date = Date, option = Option}, mnesia:write(?TAB_NAME, R, write) end end, case mnesia:transaction(Fun) of {atomic, ok} -> ok; {aborted, Reason} -> {error, Reason} end. -spec delete(SceneId :: integer(), Date :: calendar:date()) -> ok | {error, Reason :: any()}. delete(SceneId, Date) when is_integer(SceneId), is_tuple(Date) -> case mnesia:transaction(fun() -> mnesia:delete(?TAB_NAME, {SceneId, Date}, write) end) of {atomic, ok} -> ok; {aborted, Reason} -> {error, Reason} end. -spec table_size() -> integer(). table_size() -> mnesia:table_info(?TAB_NAME, size). to_map(#totalizator{scene_id = SceneId, option = #option{success_num = SuccessNum, fail_num = FailNum}}) -> #{<<"scene_id">> => SceneId, <<"success_num">> => SuccessNum, <<"fail_num">> => FailNum}. format_date({Year, Month, Day}) -> iolist_to_binary(io_lib:format("~b-~2..0b-~2..0b", [Year, Month, Day])).