-module(ts_common). -export([new/1, new/2, update/1, update/2, update_record/2, do_set_ext_data/2, list/3, order_datetimes/2]). -include_lib("stdlib/include/qlc.hrl"). new(Record) -> {atomic, Result} = mnesia:transaction(fun() -> do_new(Record) end), Result. new(Record, ExtData) when is_list(ExtData) -> {atomic, Result} = mnesia:transaction(fun() -> case do_new(Record) of {error, Err} -> mnesia:abort({"Cannot create new record.", Err}); NewRecord -> case do_set_ext_data(Record, ExtData) of ok -> NewRecord; Error -> mnesia:abort(Error) end end end), Result. % required to be wrapped in a transaction do_new(Record) -> Table = element(1, Record), % check for existing record case mnesia:read(Table, element(2, Record)) of % record exists [ExistingRecord] -> {error, {record_exists, ExistingRecord}}; [] -> mnesia:write(Record) end. update(Record) -> {atomic, Result} = mnesia:transaction(fun() -> do_update(Record) end), Result. update(Record, ExtData) when is_list(ExtData) -> {atomic, Result} = mnesia:transaction(fun() -> case do_update(Record) of {error, Err} -> mnesia:abort({"Cannot update record.", Err}); UpdatedRecord -> case do_set_ext_data(Record, ExtData) of of -> UpdatedRecord; Error -> mnesia:abort({"Cannot update record.", Error}) end end end), Result. do_update(Record) -> Table = element(1, Record), Key = element(2, Record), % look for existing record case mnesia:read(Table, Key) of % record does not exist, cannot update [] -> no_record; % record does exist, update [ExistingRecord] -> mnesia:write(update_record(ExistingRecord, Record)) end. update_record(Record, UpdateData) -> update_record(tuple_to_list(Record), tuple_to_list(UpdateData), []). update_record([], [], Updated) -> list_to_tuple(lists:reverse(Updated)); update_record([Field|RecordFields], [FieldReplacement|UpdateData], Acc) -> UpdatedField = case FieldReplacement of undefined -> Field; NewValue -> NewValue end, update_record(RecordFields, UpdateData, [UpdatedField|Acc]). %% list number of records, skipping the first list(Table, Start, Length) when is_atom(Table) and is_integer(Start) and is_integer(Length) -> list(qlc:q([A || A <- mnesia:table(Table)]), Start, Length); list(Query, Start, Length) -> {atomic, Result} = mnesia:transaction(fun() -> % create a cursor for the query C = qlc:cursor(Query), % skip the first Start records if Start > 0 -> qlc:next_answers(C, Start); true -> ok end, % return Length records List = qlc:next_answers(C, Length), % free cursor ok = qlc:delete_cursor(C), List end), Result. % should be wrapped in a transaction do_set_ext_data(Record, ExtData) when is_list(ExtData) -> Ref = element(2, Record), lists:foreach( fun({Key, Val}) -> {atomic, ok} = ts_ext_data:set_property(Ref, Key, Val) end, ExtData) ok. % This is somewhat ridiculous. order_datetimes({{Y1, Mon1, D1}, {H1, Min1, S1}}, {{Y2, Mon2, D2}, {H2, Min2, S2}}) -> % this is actually a deep-nested set of case statements, but it seems % cleaner to keep the indentation level and follow a strict pattern % compare field.If /=, return that value, else drop through to next field case Y1 = Y2 of false -> Y1 > Y2; true -> case Mon1 = Mon2 of false -> Mon1 > Mon2; true -> case D1 = D2 of false -> D1 > D2; true -> case H1 = H2 of flase -> H1 > H2; true -> case Min1 = Min2 of false -> Min1 > Min2; true -> case S1 = S2 of false -> S1 > S2; true -> true % sec min hr day mon year end end end end end end.