Starting DB implementation.

Added Makefile, id_counter.erl, and yaws.conf.
Created ts_common module. Will contain common DB code. So far only list/3.
Created ts_timeline module. DB code for storing timeline entries.
Created ts_entry module, DB code for storing timelin entries.
This commit is contained in:
Jonathan Bernard 2011-01-28 06:49:47 -06:00
parent 111da51c73
commit 495336fc58
7 changed files with 165 additions and 0 deletions

38
Makefile Normal file
View File

@ -0,0 +1,38 @@
MODS = $(wildcard src/*.erl)
BEAMS = $(MODS:src/%.erl=ebin/%.beam)
TEST_MODS = $(wildcard test/*.erl)
TEST_BEAMS = $(TEST_MODS:test/%.erl=test/%.beam)
all : compile test
compile : $(BEAMS)
compile-test : $(TEST_BEAMS)
test : start-test-server run-test stop-test-server
test-shell : compile compile-test
@echo Starting an interactive YAWS shell with test paths loaded.
@yaws -i --pa test --id test_inst
run-test : compile compile-test
@erl -pa ./ebin -pa ./test -run timestamper_api_tests test -run init stop -noshell
start-test-server :
@yaws -D --id test_inst
stop-test-server :
@yaws --stop --id test_inst
clean:
rm -rf ebin/* erl_crash.dump test/*.beam
init:
-mkdir ebin
ebin/%.beam : src/%.erl
erlc -W -o ebin $<
test/%.beam : test/%.erl
@echo Compiling sources...
erlc -W -o test $<

23
src/id_counter.erl Normal file
View File

@ -0,0 +1,23 @@
-module(id_counter).
-export([create_table/1, next_counter/1, dirty_next_counter/1]).
-include("vbs_db_records.hrl").
%% Create the table structure for Mnesia
create_table(Opts) ->
mnesia:create_table(id_counter, Opts ++
[{attributes, record_info(fields, id_counter)}]).
%% Get the next id for a given name
next_counter(Name) ->
Rec = case mnesia:read({id_counter, Name}) of
[] -> #id_counter{name=Name, next_value=0};
[Val] -> Val
end,
NextRec = Rec#id_counter{next_value = Rec#id_counter.next_value+ 1},
ok = mnesia:write(NextRec),
Rec#id_counter.next_value.
%% Get the next id for a given name
dirty_next_counter(Name) ->
mnesia:dirty_update_counter(id_counter, Name, 1) - 1.

29
src/ts_common.erl Normal file
View File

@ -0,0 +1,29 @@
-module(ts_common).
-export([list/3]).
-include_lib("stdlib/include/qlc.hrl").
%% list <Length> number of records, skipping the first <Start>
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.

12
src/ts_db_records.hrl Normal file
View File

@ -0,0 +1,12 @@
-record(ts_timeline, {
ref, % {username, timelineid}
created,% {{year, month, day}, {hour, minute, second}}
desc
}).
-record(ts_entry, {
ref, % {username, timelineid, eventid}
timestamp, % {{year, month, day}, {hour, minute, second}}
mark, % String description of entry
notes % String with further notes about the entry
}).

19
src/ts_entry.erl Normal file
View File

@ -0,0 +1,19 @@
-module(ts_entry).
-export([create_table/1, new/1, update/1, list/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()) ->
{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}},
ok = mnesia:write(NewRow),
NewRow end),
{ok, NewRow}.

34
src/ts_timeline.erl Normal file
View File

@ -0,0 +1,34 @@
-module(ts_timeline).
-export([create_table/1, new/1, update/1, list/3]).
-include("ts_db_records.hrl").
-include_lib("stdlib/include/qlc.hrl").
create_table(TableOpts) ->
mnesia:create_table(ts_timeline,
TableOpts ++ [{attributes, record_info(fields, ts_timeline)},
{type, ordered_set}]).
new(TR = #ts_timeline{}) ->
case mnesia:dirty_read(ts_timeline, TR#ts_timeline.ref) of
[ExistingRecord] -> {error, {record_exists, ExistingRecord}};
[] -> mnesia:dirty_write(TR)
end.
update(TR = #ts_timeline{}) ->
% look for the existing record
case mnesia:dirty_read(ts_timeline, TR#ts_timeline.ref) of
% record does not exist
[] -> no_record;
% record exists, update
[Record] -> mnesia:dirty_write(TR)
end.
list(Username, Start, Length) ->
ts_common:list(
qlc:q([T || T <- mnesia:table(ts_timeline),
T#ts_timeline.ref = {Username, _}]),
Start, Length).

10
yaws.conf Normal file
View File

@ -0,0 +1,10 @@
ebin_dir = /home/jdbernard/projects/timestamper/web-app/ebin
#include_dir = /home/jdbernard/projects/timestamper/web-app/src
runmod = timestamper
<server timestamper-test>
port = 8000
listen = /home/jdbernard/projects/timestamper/web-app/www
appmods = timestamper_api
</server>