Continuing work on the API.
The id_counter module now includes the record directly in the source. Fixed many typos and small syntax errors. Added ts_api:dispatch_user/2 to handle different HTTP methods. Added method placeholder stubs to ts_api. Implemented ts_api:list_entries/3. Added ts_user record and ts_user module. Implemented ts_entry:list/4, the more generic guts of the other list functions. Created ts_entry:list_asc/3 and ts_entry:list_desc/3. Fixed ts_json:encode_datetime/1.
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
-module(ts_entry).
|
||||
-export([create_table/1, new/1, update/1, lookup/3, list/3]).
|
||||
-export([create_table/1, new/1, update/1, lookup/3, list_asc/3, list_desc/3]).
|
||||
|
||||
-include("ts_db_records.hrl").
|
||||
-include_lib("stdlib/include/qlc.hrl").
|
||||
@ -7,10 +7,10 @@
|
||||
create_table(TableOpts) ->
|
||||
mnesia:create_table(ts_entry,
|
||||
TableOpts ++ [{attributes, record_info(fields, ts_entry)},
|
||||
{type, ordered_set}, {index, timestamp}]).
|
||||
{type, ordered_set}, {index, [timestamp]}]).
|
||||
|
||||
new(ER = #ts_entry()) ->
|
||||
{atmoic, NewRow) = mnesia:transaction(fun() ->
|
||||
new(ER = #ts_entry{}) ->
|
||||
{atmoic, NewRow} = mnesia:transaction(fun() ->
|
||||
{Username, TimelineId, _} = ER#ts_entry.ref,
|
||||
NextId = id_counter:next_counter(ts_entry_id),
|
||||
NewRow = ER#ts_entry{ref = {Username, TimelineId, NextId}},
|
||||
@ -18,7 +18,7 @@ new(ER = #ts_entry()) ->
|
||||
NewRow end),
|
||||
{ok, NewRow}.
|
||||
|
||||
update(ER = #ts_entry()) ->
|
||||
update(ER = #ts_entry{}) ->
|
||||
|
||||
% look for existing record
|
||||
case mnesia:dirty_read(ts_entry, ER#ts_entry.ref) of
|
||||
@ -34,30 +34,60 @@ lookup(Username, TimelineId, EntryId) ->
|
||||
[Entry] -> Entry
|
||||
end.
|
||||
|
||||
list({Username, Timeline}, Start, Length)
|
||||
list({Username, Timeline}, Start, Length, OrderFun)
|
||||
when is_integer(Start) and is_integer(Length) ->
|
||||
ts_common:list(
|
||||
qlc:q([E || E <- mnesia:table(ts_entry),
|
||||
E#ts_entry.ref =:= {Username, Timeline, _}]_,
|
||||
Start, Length).
|
||||
|
||||
list({Username, Timeline}, StartDateTime, EndDateTime) ->
|
||||
|
||||
{atomic, Entries} = mnesia:transaction(fun() ->
|
||||
% match the username and timeline
|
||||
MatchHead = #ts_entry{ref = {Username, Timeline, '_'}, _='_'},
|
||||
|
||||
StartSeconds = calendar:datetime_to_gregorian_seconds(StartDateTime),
|
||||
EndSeconds = calendar:datetime_to_gregorian_seconds(EndDateTime),
|
||||
|
||||
% create the query that will select these records
|
||||
Q = qlc:q([E || E <- mnesia:table(ts_entry),
|
||||
E#ts_entry.timestamp >= StartSeconds,
|
||||
E#ts_entry.timestamp < EndSeconds]),
|
||||
|
||||
% sort by timestamp
|
||||
SortedQ = qlc:sort(Q, {order, fun(A, B) ->
|
||||
A#ts_entry.timestamp > B#ts_entry.timestamp end}),
|
||||
|
||||
% return
|
||||
qlc:e(SortedQ)
|
||||
% select all records that match
|
||||
mnesia:select(ts_entry, [{MatchHead, [], ['$_']}]
|
||||
end),
|
||||
Entries.
|
||||
|
||||
% sort
|
||||
SortedEntries = lists:sort(OrderFun, Entries),
|
||||
|
||||
% return only the range selected.
|
||||
% TODO: can we do this without selecting all entries?
|
||||
lists:sublist(SortedEntries, Start, Length);
|
||||
|
||||
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.
|
||||
|
Reference in New Issue
Block a user