-module(ts_entry). -export([create_table/1, new/1, new/2, update/1, update/2, write/1, delete/1, lookup/3, list_asc/3, list_desc/3]). -include("ts_db_records.hrl"). -include_lib("stdlib/include/qlc.hrl"). create_table(TableOpts) -> mnesia:create_table(ts_entry, TableOpts ++ [{attributes, record_info(fields, ts_entry)}, {type, ordered_set}, {index, [timestamp]}]). new(ER = #ts_entry{}) -> {atomic, NewRow} = mnesia:transaction(fun() -> do_new(ER) end), {ok, NewRow}. new(ER = #ts_entry{}, ExtData) when is_list(ExtData) -> {atomic, NewRow} = mnesia:transaction(fun() -> NewRow = do_new(ER), ts_common:do_set_ext_data(ER, ExtData), NewRow end), NewRow. do_new(ER = #ts_entry{}) -> {Username, TimelineId, _} = ER#ts_entry.ref, NextId = id_counter:next_counter(ts_entry_id), NewRow = ER#ts_entry{ref = {Username, TimelineId, NextId}}, ok = mnesia:write(NewRow), NewRow. update(ER = #ts_entry{}) -> ts_common:update(ER). update(ER = #ts_entry{}, ExtData) when is_list(ExtData) -> ts_common:update(ER, ExtData). write(ER = #ts_entry{}) -> mnesia:dirty_write(ER). lookup(Username, TimelineId, EntryId) -> case mnesia:dirty_read(ts_entry, {Username, TimelineId, EntryId}) of [] -> no_record; [Entry] -> Entry end. delete(ER = #ts_entry{}) -> mnesia:dirty_delete_object(ER). list({Username, Timeline}, Start, Length, OrderFun) when is_integer(Start) and is_integer(Length) -> {atomic, Entries} = mnesia:transaction(fun() -> % match the username and timeline MatchHead = #ts_entry{ref = {Username, Timeline, '_'}, _='_'}, % select all records that match mnesia:select(ts_entry, [{MatchHead, [], ['$_']}]) end), % sort SortedEntries = lists:sort(OrderFun, Entries), % return only the range selected. % TODO: can we do this without selecting all entries? case length(SortedEntries) > Start of true -> lists:sublist(SortedEntries, Start + 1, Length); false -> [] end; list({Username, Timeline}, StartDateTime, EndDateTime, OrderFun) -> % compute the seconds from datetimes StartSeconds = calendar:datetime_to_gregorian_seconds(StartDateTime), EndSeconds = calendar:datetime_to_gregorian_seconds(EndDateTime), % select all entries from the timeline that are within the time range {atomic, Entries} = mnesia:transaction(fun() -> % match the username and timeline id MatchHead = #ts_entry{ref = {Username, Timeline, '_'}, timestamp='$1', _='_'}, % guards for the time range StartGuard = {'>=', '$1', StartSeconds}, EndGuard = {'<', '$1', EndSeconds}, mnesia:select(ts_entry, [{MatchHead, [StartGuard, EndGuard], ['$_']}]) end), % sort lists:sort(OrderFun, Entries). list_asc(TimelineRef, Start, Length) when is_integer(Start) and is_integer(Length) -> list(TimelineRef, Start, Length, fun timestamp_asc/2); list_asc(TimelineRef, StartDateTime, EndDateTime) -> list(TimelineRef, StartDateTime, EndDateTime, fun timestamp_asc/2). list_desc(TimelineRef, Start, Length) when is_integer(Start) and is_integer(Length) -> list(TimelineRef, Start, Length, fun timestamp_desc/2); list_desc(TimelineRef, StartDateTime, EndDateTime) -> list(TimelineRef, StartDateTime, EndDateTime, fun timestamp_desc/2). timestamp_asc(E1, E2) -> E1#ts_entry.timestamp > E2#ts_entry.timestamp. timestamp_desc(E1, E2) -> E1#ts_entry.timestamp < E2#ts_entry.timestamp.