Much cleaner, but not working, because I have a circular loop
This commit is contained in:
30
src/ezic.erl
30
src/ezic.erl
@@ -36,7 +36,7 @@ localtime(TzName) ->
|
||||
|
||||
utc_to_local(UTCDatetime, TzName) ->
|
||||
NormalDatetime= ezic_date:normalize(UTCDatetime, u),
|
||||
#flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db_ets:flatzone(NormalDatetime, TzName),
|
||||
#flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db:flatzone(NormalDatetime, TzName),
|
||||
|
||||
ezic_date:add_offset(
|
||||
ezic_date:add_offset(
|
||||
@@ -47,7 +47,7 @@ utc_to_local(UTCDatetime, TzName) ->
|
||||
|
||||
local_to_utc(LocalDatetime, TzName) ->
|
||||
NormalDatetime= ezic_date:normalize(LocalDatetime, w),
|
||||
#flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db_ets:flatzone(NormalDatetime, TzName),
|
||||
#flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db:flatzone(NormalDatetime, TzName),
|
||||
|
||||
ezic_date:add_offset(
|
||||
ezic_date:add_offset(
|
||||
@@ -84,7 +84,7 @@ dev() ->
|
||||
% ezic_flatten:flatten_all_zones(Zones),
|
||||
|
||||
application:start(ezic),
|
||||
ezic_db_ets:flatzone({{2010,11,17}, #tztime{time={23,42,0}}}, "America/Los_Angeles"),
|
||||
ezic_db:flatzone({{2010,11,17}, #tztime{time={23,42,0}}}, "America/Los_Angeles"),
|
||||
|
||||
ok.
|
||||
|
||||
@@ -94,8 +94,8 @@ zf() ->
|
||||
|
||||
|
||||
reflatten() ->
|
||||
ezic_db_ets:wipe(flatzone),
|
||||
ezic_db_ets:flatten().
|
||||
ezic_db:wipe(flatzone),
|
||||
ezic_db:flatten().
|
||||
|
||||
|
||||
|
||||
@@ -113,20 +113,20 @@ test() ->
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
current_as_of_utc(UTCDatetime, TzName) ->
|
||||
CZone= ezic_zone:current_as_of_utc(UTCDatetime, TzName),
|
||||
RuleName= CZone#zone.rule,
|
||||
Rules= ezic_db_ets:rules(RuleName),
|
||||
CRule= ezic_rule:current_as_of_utc(UTCDatetime, Rules),
|
||||
{ok, CZone, CRule}.
|
||||
%current_as_of_utc(UTCDatetime, TzName) ->
|
||||
% CZone= ezic_zone:current_as_of_utc(UTCDatetime, TzName),
|
||||
% RuleName= CZone#zone.rule,
|
||||
% Rules= ezic_db:rules(RuleName),
|
||||
% CRule= ezic_rule:current_as_of_utc(UTCDatetime, Rules),
|
||||
% {ok, CZone, CRule}.
|
||||
|
||||
|
||||
%%current_as_of_local(Datetime, TzName) ->
|
||||
%% not_done.
|
||||
|
||||
|
||||
time_offset(Zone, Rule) ->
|
||||
OffsetSec= ezic_zone:offset_sec(Zone),
|
||||
DSTSec= ezic_rule:dst_sec(Rule),
|
||||
OffsetSec + DSTSec.
|
||||
%time_offset(Zone, Rule) ->
|
||||
% OffsetSec= ezic_zone:offset_sec(Zone),
|
||||
% DSTSec= ezic_rule:dst_sec(Rule),
|
||||
% OffsetSec + DSTSec.
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ when is_integer(Y1), is_integer(Y2)
|
||||
compare({Date1, #tztime{time=Time1, flag=F}}
|
||||
, {Date2, #tztime{time=Time2, flag=F}}) ->
|
||||
|
||||
Date1 =< Date2 orelse Time1 =< time2;
|
||||
Date1 =< Date2 orelse Time1 =< Time2;
|
||||
|
||||
compare(X,Y) ->
|
||||
erlang:error(bad_dates, [X,Y]).
|
||||
|
||||
214
src/ezic_db.erl
214
src/ezic_db.erl
@@ -1,149 +1,125 @@
|
||||
-module(ezic_db).
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("stdlib/include/qlc.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
|
||||
-export([
|
||||
zones/1
|
||||
, rules/1
|
||||
, flatzone/2
|
||||
%, insert/2
|
||||
, get_all/1
|
||||
, insert_all/1
|
||||
, wipe/1
|
||||
, flatten/0
|
||||
]).
|
||||
|
||||
-export([
|
||||
wipe/0
|
||||
, wipe/1
|
||||
, init/0
|
||||
, insert_all/1
|
||||
, get_all/1
|
||||
]).
|
||||
start_link/0
|
||||
, init/1
|
||||
, code_change/3
|
||||
, handle_call/3
|
||||
, handle_cast/2
|
||||
, handle_info/2
|
||||
, terminate/2
|
||||
]).
|
||||
|
||||
|
||||
-define(create(Record),
|
||||
{atomic, ok} = mnesia:create_table(Record,
|
||||
[{type, bag}
|
||||
, {disc_copies, [node()]}
|
||||
, {attributes, record_info(fields, Record)}
|
||||
])).
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% PUBLIC API
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% READ - db reading methods
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
zones(TzName) ->
|
||||
gen_server:call(?MODULE, {zones, TzName}).
|
||||
|
||||
|
||||
rules(TzName) ->
|
||||
gen_server:call(?MODULE, {rules, TzName}).
|
||||
|
||||
% retrieve all zones by name
|
||||
zones(Name) ->
|
||||
F = fun()->
|
||||
Q = qlc:q([Z || Z=#zone{name=N} <- mnesia:table(zone), N=:=Name]),
|
||||
qlc:e(Q)
|
||||
end,
|
||||
{atomic, Zones}= mnesia:transaction(F),
|
||||
Zones.
|
||||
|
||||
% retrieve all rules by name
|
||||
rules(Name) ->
|
||||
F = fun()->
|
||||
Q = qlc:q([R || R=#rule{name=N} <- mnesia:table(rule), N=:=Name]),
|
||||
qlc:e(Q)
|
||||
end,
|
||||
{atomic, Rules}= mnesia:transaction(F),
|
||||
Rules.
|
||||
|
||||
% get all records from table
|
||||
get_all(Tab) when is_atom(Tab) ->
|
||||
F = fun() ->
|
||||
Q = qlc:q([R || R<- mnesia:table(Tab)]),
|
||||
qlc:e(Q)
|
||||
end,
|
||||
{atomic, Ret}= mnesia:transaction(F),
|
||||
Ret.
|
||||
|
||||
%% get a flatzone for a specific date
|
||||
%% Date :: {date(), #tztime{}}
|
||||
%% returns #flatzone{}
|
||||
%% or throws either error:
|
||||
%% * {ambiguous_zone, [Z1,Z2,...]}
|
||||
%% * {no_zone}
|
||||
flatzone(Date, TzName) ->
|
||||
%% @todo validate Date
|
||||
F = fun()->
|
||||
Q = qlc:q(
|
||||
[Fz || Fz=#flatzone{tzname=N} <- mnesia:table(flatzone)
|
||||
, N=:=TzName
|
||||
, ezic_flatten:contains_date(Fz, Date)]),
|
||||
qlc:e(Q)
|
||||
end,
|
||||
{atomic, FlatZones}= mnesia:transaction(F),
|
||||
|
||||
case length(FlatZones) of
|
||||
1 ->
|
||||
hd(FlatZones);
|
||||
2 ->
|
||||
erlang:error(ambiguous_zone, FlatZones);
|
||||
0 ->
|
||||
erlang:error(no_zone);
|
||||
_ ->
|
||||
erlang:error(should_not_happen, {FlatZones, Date, TzName})
|
||||
end.
|
||||
|
||||
gen_server:call(?MODULE, {flatzone, Date, TzName}).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% ADMIN - initialization and administration methods
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
% initialize the db
|
||||
init() ->
|
||||
create_tabs(mnesia:create_schema([node()])),
|
||||
mnesia:wait_for_tables([rule, zone, link, leap, flatzone], 3000).
|
||||
|
||||
|
||||
% WARNING: deletes all db files
|
||||
wipe() ->
|
||||
mnesia:stop(),
|
||||
mnesia:delete_schema([node()]).
|
||||
|
||||
|
||||
|
||||
% WARNING: deletes all entries in table Tab
|
||||
wipe(Tab) ->
|
||||
mnesia:transaction(
|
||||
fun()->
|
||||
mnesia:delete(Tab, '_', write)
|
||||
end).
|
||||
|
||||
|
||||
|
||||
create_tabs(ok) ->
|
||||
mnesia:start(),
|
||||
|
||||
?create(rule),
|
||||
?create(zone),
|
||||
?create(link),
|
||||
?create(leap),
|
||||
?create(flatzone),
|
||||
|
||||
ok;
|
||||
create_tabs({error, {_, {already_exists,_}}}) ->
|
||||
mnesia:start(),
|
||||
ok;
|
||||
create_tabs(E) ->
|
||||
?debugVal(E).
|
||||
get_all(Tab) ->
|
||||
gen_server:call(?MODULE, {all, Tab}).
|
||||
|
||||
|
||||
insert_all(Records) ->
|
||||
mnesia:transaction(
|
||||
fun() ->
|
||||
lists:foreach(
|
||||
fun(R)-> mnesia:write(R) end,
|
||||
Records)
|
||||
end).
|
||||
|
||||
gen_server:call(?MODULE, {insert_all, Records}).
|
||||
|
||||
|
||||
%wipe() ->
|
||||
% gen_server:call(?MODULE, {wipe}).
|
||||
|
||||
|
||||
wipe(Tab) ->
|
||||
gen_server:call(?MODULE, {wipe, Tab}).
|
||||
|
||||
|
||||
flatten() ->
|
||||
gen_server:call(?MODULE, {flatten}).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% GEN_SERVER
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||
|
||||
init(_) ->
|
||||
ezic_db_ets:init(),
|
||||
{ok, []}.
|
||||
|
||||
%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
%% DB Lookup
|
||||
%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
handle_call({zones, Name}, _, State) ->
|
||||
Matches= ezic_db_ets:zones(Name),
|
||||
{reply, Matches, State};
|
||||
handle_call({rules, Name}, _, State) ->
|
||||
Matches= ezic_db_ets:rules(Name),
|
||||
{reply, Matches, State};
|
||||
handle_call({all, Tab}, _, State) ->
|
||||
Matches= ezic_db_ets:get_all(Tab),
|
||||
{reply, Matches, State};
|
||||
handle_call({flatzone, Date, Name}, _, State) ->
|
||||
Result= ezic_db_ets:flatzone(Date, Name),
|
||||
{reply, Result, State};
|
||||
handle_call({insert_all, Records}, _, State) ->
|
||||
ezic_db_ets:insert_all(Records),
|
||||
{noreply, State};
|
||||
handle_call({wipe, Tab}, _, State) ->
|
||||
Result= ezic_db_ets:wipe(Tab),
|
||||
{reply, Result, State};
|
||||
handle_call({flatten}, _, State) ->
|
||||
Result= ezic_flatten:flatten(),
|
||||
{reply, Result, State};
|
||||
handle_call(_, _, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
|
||||
%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
%% Other gen_server
|
||||
%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
code_change(_, State, _) ->
|
||||
{ok, State}.
|
||||
|
||||
|
||||
handle_cast(_, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(_, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_, _State) ->
|
||||
ok.
|
||||
|
||||
@@ -2,54 +2,57 @@
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
-define(DB_FILENAME, "db.e2f").
|
||||
|
||||
-export([
|
||||
zones/1
|
||||
init/0
|
||||
, zones/1
|
||||
, rules/1
|
||||
, flatzone/2
|
||||
, all/1
|
||||
%, insert_all/1
|
||||
%, insert/2
|
||||
, get_all/1
|
||||
, insert_all/1
|
||||
, wipe/1
|
||||
, flatten/0
|
||||
]).
|
||||
|
||||
|
||||
-export([
|
||||
start_link/0
|
||||
, init/1
|
||||
, code_change/3
|
||||
, handle_call/3
|
||||
, handle_cast/2
|
||||
, handle_info/2
|
||||
, terminate/2
|
||||
]).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% PUBLIC API
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
zones(TzName) ->
|
||||
gen_server:call(?MODULE, {zones, TzName}).
|
||||
ets:select(zone, [{#zone{name=TzName, _='_'}, [], ['$_']}]).
|
||||
|
||||
|
||||
rules(TzName) ->
|
||||
gen_server:call(?MODULE, {rules, TzName}).
|
||||
ets:select(rule, [{#rule{name=TzName, _='_'}, [], ['$_']}]).
|
||||
|
||||
|
||||
flatzone(Date, TzName) ->
|
||||
gen_server:call(?MODULE, {flatzone, Date, TzName}).
|
||||
FlatZones= ets:select(flatzone, ezic_flatten:ms(Date, TzName)),
|
||||
case length(FlatZones) of
|
||||
1 ->
|
||||
hd(FlatZones);
|
||||
2 ->
|
||||
erlang:error(ambiguous_zone, FlatZones);
|
||||
0 ->
|
||||
erlang:error(no_zone);
|
||||
_ ->
|
||||
erlang:error(should_not_happen, {FlatZones, Date, TzName})
|
||||
end.
|
||||
|
||||
|
||||
all(Tab) ->
|
||||
gen_server:call(?MODULE, {all, Tab}).
|
||||
get_all(Tab) ->
|
||||
ets:lookup(Tab, Tab).
|
||||
|
||||
|
||||
%insert_all(Records) ->
|
||||
% gen_server:call(?MODULE, {insert_all, Records}).
|
||||
insert_all(Records) ->
|
||||
Zones= [ZI || ZI <- Records, ZI = #zone{}],
|
||||
ets:insert(zone, Zones),
|
||||
Rules= [RI || RI <- Records, RI = #rule{}],
|
||||
ets:insert(rule, Rules),
|
||||
FlatZones= [FZ || FZ <- Records, FZ = #flatzone{}],
|
||||
ets:insert(flatzone, FlatZones).
|
||||
|
||||
|
||||
%wipe() ->
|
||||
@@ -57,81 +60,78 @@ all(Tab) ->
|
||||
|
||||
|
||||
wipe(Tab) ->
|
||||
gen_server:call(?MODULE, {wipe, Tab}).
|
||||
ets:delete(Tab, Tab).
|
||||
|
||||
|
||||
flatten() ->
|
||||
gen_server:call(?MODULE, {flatten}).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% GEN_SERVER
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||
|
||||
init(_) ->
|
||||
ezic_db_ets_admin:init().
|
||||
init() ->
|
||||
{ok, DbDir}= application:get_env(db_dir),
|
||||
Filename= filename:join(DbDir, ?DB_FILENAME),
|
||||
case db_sane(Filename) of
|
||||
true -> load_tabfile(Filename);
|
||||
false -> create_tables(Filename)
|
||||
end,
|
||||
{ok, []}.
|
||||
|
||||
%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
%% DB Lookup
|
||||
%% Private functions for initializing ets
|
||||
%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
handle_call({zones, Name}, _, State) ->
|
||||
Matches= ets:select(zone, [{#zone{name=Name, _='_'}, [], ['$_']}]),
|
||||
{reply, Matches, State};
|
||||
handle_call({rules, Name}, _, State) ->
|
||||
Matches= ets:select(rule, [{#rule{name=Name, _='_'}, [], ['$_']}]),
|
||||
{reply, Matches, State};
|
||||
handle_call({all, Tab}, _, State) ->
|
||||
Matches= ets:lookup(Tab, Tab),
|
||||
{reply, Matches, State};
|
||||
handle_call({flatzone, Date, Name}, _, State) ->
|
||||
FlatZones= ets:select(flatzone, ezic_flatten:ms(Date, Name)),
|
||||
Result= case length(FlatZones) of
|
||||
1 ->
|
||||
hd(FlatZones);
|
||||
2 ->
|
||||
erlang:error(ambiguous_zone, FlatZones);
|
||||
0 ->
|
||||
erlang:error(no_zone);
|
||||
_ ->
|
||||
erlang:error(should_not_happen, {FlatZones, Date, Name})
|
||||
end,
|
||||
{reply, Result, State};
|
||||
%handle_call({insert_all, Records}, _, Ets) ->
|
||||
% Result= ets:insert(Ets, Records),
|
||||
% {reply, Result, Ets};
|
||||
%handle_call({wipe}, _, Ets) ->
|
||||
% Result= ets:delete(Ets),
|
||||
% {reply, Result, Ets};
|
||||
handle_call({wipe, Tab}, _, State) ->
|
||||
Result= ets:delete(Tab, Tab),
|
||||
{reply, Result, State};
|
||||
handle_call({flatten}, _, State) ->
|
||||
Result= ezic_flatten:flatten(),
|
||||
{reply, Result, State};
|
||||
handle_call(_, _, State) ->
|
||||
{noreply, State}.
|
||||
%% -> true if table exists
|
||||
db_sane(Filename) ->
|
||||
%% @todo ensure data is present for each record type.
|
||||
|
||||
case ets:tabfile_info(Filename) of
|
||||
{ok, _} -> true;
|
||||
{error, _} -> false
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
%% Other gen_server
|
||||
%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
%% creates the dets table and populates it.
|
||||
create_tables(Filename) ->
|
||||
{ok, Zones, Rules, _, _} = ezic_record:separate(ezic_loader:load()),
|
||||
|
||||
ets:new(zone, [duplicate_bag, named_table]),
|
||||
true = ets:insert(zone, Zones),
|
||||
|
||||
code_change(_, State, _) ->
|
||||
{ok, State}.
|
||||
ets:new(rule, [duplicate_bag, named_table]),
|
||||
true = ets:insert(rule, Rules),
|
||||
|
||||
ets:new(flatzone, [duplicate_bag, named_table]),
|
||||
io:format("~p~n", [Rules]),
|
||||
ezic_flatten:flatten(),
|
||||
|
||||
handle_cast(_, State) ->
|
||||
{noreply, State}.
|
||||
% combine into one ets
|
||||
Ets= ets:new(ezic_db_ets, [duplicate_bag]),
|
||||
ets:insert(Ets, ets:lookup(zone, zone)),
|
||||
ets:insert(Ets, ets:lookup(rule, rule)),
|
||||
ets:insert(Ets, ets:lookup(flatzone, flatzone)),
|
||||
|
||||
handle_info(_, State) ->
|
||||
{noreply, State}.
|
||||
% save to disk
|
||||
ets:tab2file(Ets, Filename),
|
||||
|
||||
ets:delete(Ets),
|
||||
|
||||
terminate(_, State) ->
|
||||
ok.
|
||||
|
||||
|
||||
|
||||
%% loads or creates the dets table.
|
||||
load_tabfile(Filename) ->
|
||||
{ok, Ets}= ets:file2tab(Filename),
|
||||
|
||||
Zones= ets:lookup(Ets, zone),
|
||||
ets:new(zone, [duplicate_bag, named_table]),
|
||||
ets:insert(zone, Zones),
|
||||
|
||||
Rules= ets:lookup(Ets, rule),
|
||||
ets:new(rule, [duplicate_bag, named_table]),
|
||||
ets:insert(rule, Rules),
|
||||
|
||||
FlatZones= ets:lookup(Ets, flatzone),
|
||||
ets:new(flatzone, [duplicate_bag, named_table]),
|
||||
ets:insert(flatzone, FlatZones),
|
||||
|
||||
ets:delete(Ets),
|
||||
ok.
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
-module(ezic_db_ets_admin).
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-define(TABS, [rule, zone, leap, flatzone]).
|
||||
-define(DB_FILENAME, "db.e2f").
|
||||
-define(DETS_OPTS, []).
|
||||
-define(ETS_OPTS, [named_table]).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-export([
|
||||
init/0
|
||||
, wipe/0
|
||||
, insert_all/1
|
||||
, wipe/1
|
||||
]).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% ADMIN API
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
% Entire DB
|
||||
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
%% if dets tables exist,
|
||||
%% load stored tables
|
||||
%% else
|
||||
%% create all ets tables as named tables
|
||||
%% load data
|
||||
init() ->
|
||||
{ok, DbDir}= application:get_env(db_dir),
|
||||
Filename= filename:join(DbDir, ?DB_FILENAME),
|
||||
case db_sane(Filename) of
|
||||
true -> load_tabfile(Filename);
|
||||
false -> create_tables(Filename)
|
||||
end,
|
||||
{ok, []}.
|
||||
|
||||
|
||||
% erases all data
|
||||
wipe() ->
|
||||
not_done.
|
||||
|
||||
|
||||
% inserts all records into the appropriate db
|
||||
insert_all(Record) ->
|
||||
not_done.
|
||||
|
||||
|
||||
|
||||
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
% Single Table
|
||||
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
% erases date for one table
|
||||
wipe(Tab) ->
|
||||
ezic_db_ets:wipe(Tab).
|
||||
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% PRIVATE
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
%% -> true if table exists
|
||||
db_sane(Filename) ->
|
||||
%% @todo ensure data is present for each record type.
|
||||
|
||||
case ets:tabfile_info(Filename) of
|
||||
{ok, _} -> true;
|
||||
{error, _} -> false
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%% creates the dets table and populates it.
|
||||
create_tables(Filename) ->
|
||||
{ok, Zones, Rules, _, _} = ezic_record:separate(ezic_loader:load()),
|
||||
|
||||
ets:new(zone, [duplicate_bag, named_table]),
|
||||
ets:insert(zone, Zones),
|
||||
|
||||
ets:new(rule, [duplicate_bag, named_table]),
|
||||
ets:insert(rule, Rules),
|
||||
|
||||
ets:new(flatzone, [duplicate_bag, named_table]),
|
||||
ezic_flatten:flatten(),
|
||||
|
||||
% combine into one ets
|
||||
Ets= ets:new(ezic_db_ets, [duplicate_bag]),
|
||||
ets:insert(Ets, ets:lookup(zone, zone)),
|
||||
ets:insert(Ets, ets:lookup(rule, rule)),
|
||||
ets:insert(Ets, ets:lookup(flatzone, flatzone)),
|
||||
|
||||
% save to disk
|
||||
ets:tab2file(Ets, Filename),
|
||||
|
||||
ets:delete(Ets),
|
||||
|
||||
ok.
|
||||
|
||||
|
||||
|
||||
%% loads or creates the dets table.
|
||||
load_tabfile(Filename) ->
|
||||
{ok, Ets}= ets:file2tab(Filename),
|
||||
|
||||
Zones= ets:lookup(Ets, zone),
|
||||
ets:new(zone, [duplicate_bag, named_table]),
|
||||
ets:insert(zone, Zones),
|
||||
|
||||
Rules= ets:lookup(Ets, rule),
|
||||
ets:new(rule, [duplicate_bag, named_table]),
|
||||
ets:insert(rule, Rules),
|
||||
|
||||
FlatZones= ets:lookup(Ets, flatzone),
|
||||
ets:new(flatzone, [duplicate_bag, named_table]),
|
||||
ets:insert(flatzone, FlatZones),
|
||||
|
||||
ets:delete(Ets),
|
||||
ok.
|
||||
|
||||
|
||||
|
||||
%% takes a populated dets table and converts it to an ets table.
|
||||
ets_from_dets(Dets) ->
|
||||
Ets= ets:new(tzdb, ?ETS_OPTS),
|
||||
dets:to_ets(Dets, Ets).
|
||||
145
src/ezic_db_mnesia.erl
Normal file
145
src/ezic_db_mnesia.erl
Normal file
@@ -0,0 +1,145 @@
|
||||
-module(ezic_db_mnesia).
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("stdlib/include/qlc.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
|
||||
-export([
|
||||
init/0
|
||||
, zones/1
|
||||
, rules/1
|
||||
, flatzone/2
|
||||
%, insert/2
|
||||
, get_all/1
|
||||
, insert_all/1
|
||||
, wipe/1
|
||||
]).
|
||||
|
||||
-define(create(Record),
|
||||
{atomic, ok} = mnesia:create_table(Record,
|
||||
[{type, bag}
|
||||
, {disc_copies, [node()]}
|
||||
, {attributes, record_info(fields, Record)}
|
||||
])).
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% READ - db reading methods
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
% retrieve all zones by name
|
||||
zones(Name) ->
|
||||
F = fun()->
|
||||
Q = qlc:q([Z || Z=#zone{name=N} <- mnesia:table(zone), N=:=Name]),
|
||||
qlc:e(Q)
|
||||
end,
|
||||
{atomic, Zones}= mnesia:transaction(F),
|
||||
Zones.
|
||||
|
||||
% retrieve all rules by name
|
||||
rules(Name) ->
|
||||
F = fun()->
|
||||
Q = qlc:q([R || R=#rule{name=N} <- mnesia:table(rule), N=:=Name]),
|
||||
qlc:e(Q)
|
||||
end,
|
||||
{atomic, Rules}= mnesia:transaction(F),
|
||||
Rules.
|
||||
|
||||
% get all records from table
|
||||
get_all(Tab) when is_atom(Tab) ->
|
||||
F = fun() ->
|
||||
Q = qlc:q([R || R<- mnesia:table(Tab)]),
|
||||
qlc:e(Q)
|
||||
end,
|
||||
{atomic, Ret}= mnesia:transaction(F),
|
||||
Ret.
|
||||
|
||||
%% get a flatzone for a specific date
|
||||
%% Date :: {date(), #tztime{}}
|
||||
%% returns #flatzone{}
|
||||
%% or throws either error:
|
||||
%% * {ambiguous_zone, [Z1,Z2,...]}
|
||||
%% * {no_zone}
|
||||
flatzone(Date, TzName) ->
|
||||
%% @todo validate Date
|
||||
F = fun()->
|
||||
Q = qlc:q(
|
||||
[Fz || Fz=#flatzone{tzname=N} <- mnesia:table(flatzone)
|
||||
, N=:=TzName
|
||||
, ezic_flatten:contains_date(Fz, Date)]),
|
||||
qlc:e(Q)
|
||||
end,
|
||||
{atomic, FlatZones}= mnesia:transaction(F),
|
||||
|
||||
case length(FlatZones) of
|
||||
1 ->
|
||||
hd(FlatZones);
|
||||
2 ->
|
||||
erlang:error(ambiguous_zone, FlatZones);
|
||||
0 ->
|
||||
erlang:error(no_zone);
|
||||
_ ->
|
||||
erlang:error(should_not_happen, {FlatZones, Date, TzName})
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% ADMIN - initialization and administration methods
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
% initialize the db
|
||||
init() ->
|
||||
create_tabs(mnesia:create_schema([node()])),
|
||||
mnesia:wait_for_tables([rule, zone, link, leap, flatzone], 3000).
|
||||
|
||||
|
||||
% WARNING: deletes all db files
|
||||
%wipe() ->
|
||||
% mnesia:stop(),
|
||||
% mnesia:delete_schema([node()]).
|
||||
|
||||
|
||||
|
||||
% WARNING: deletes all entries in table Tab
|
||||
wipe(Tab) ->
|
||||
mnesia:transaction(
|
||||
fun()->
|
||||
mnesia:delete(Tab, '_', write)
|
||||
end).
|
||||
|
||||
|
||||
|
||||
create_tabs(ok) ->
|
||||
mnesia:start(),
|
||||
|
||||
?create(rule),
|
||||
?create(zone),
|
||||
?create(link),
|
||||
?create(leap),
|
||||
?create(flatzone),
|
||||
|
||||
{ok, Zones, Rules, _, _} = ezic_record:separate(ezic_loader:load()),
|
||||
insert_all(Zones),
|
||||
insert_all(Rules),
|
||||
ezic_flatten:flatten(),
|
||||
|
||||
ok;
|
||||
create_tabs({error, {_, {already_exists,_}}}) ->
|
||||
mnesia:start(),
|
||||
ok;
|
||||
create_tabs(E) ->
|
||||
?debugVal(E).
|
||||
|
||||
|
||||
insert_all(Records) ->
|
||||
mnesia:transaction(
|
||||
fun() ->
|
||||
lists:foreach(
|
||||
fun(R)-> mnesia:write(R) end,
|
||||
Records)
|
||||
end).
|
||||
@@ -1,6 +1,5 @@
|
||||
-module(ezic_flatten).
|
||||
-include("include/ezic.hrl").
|
||||
-define(NODEBUG, true).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
|
||||
@@ -22,7 +21,7 @@
|
||||
|
||||
|
||||
flatten() ->
|
||||
AllZones= ets:lookup(zone, zone),
|
||||
AllZones= ezic_db:get_all(zone),
|
||||
flatten_all_zones(AllZones),
|
||||
done.
|
||||
|
||||
@@ -45,7 +44,7 @@ ms(Date, Name) ->
|
||||
|
||||
{D, #tztime{time=T, flag=F}}=Date,
|
||||
|
||||
SDate= {D,T},
|
||||
%SDate= {D,T},
|
||||
DComp= {{{D},{T}}},
|
||||
|
||||
G= ms_guards(F, DComp),
|
||||
@@ -82,22 +81,22 @@ flatten_all_zones([Z1|_]= AllZones) ->
|
||||
{CurrentZones, RestZones}= ezic_zone:split_by_name(Z1, AllZones),
|
||||
|
||||
Flats= flatten_zone_set(CurrentZones),
|
||||
ets:insert(flatzone, Flats),
|
||||
ezic_db:insert_all(Flats),
|
||||
|
||||
flatten_all_zones(RestZones).
|
||||
|
||||
|
||||
|
||||
contains_date2(FlatZone=#flatzone{utc_from=From, utc_to=To}, {Dt,#tztime{time=T, flag=F}})
|
||||
contains_date2(#flatzone{utc_from=From, utc_to=To}, {Dt,#tztime{time=T, flag=F}})
|
||||
when F=:= u; F=:= g; F=:=z ->
|
||||
Date={Dt, T},
|
||||
ezic_date:compare(From, Date) andalso ezic_date:compare(Date, To);
|
||||
|
||||
contains_date2(FlatZone=#flatzone{std_from=From, std_to=To}, {Dt,#tztime{time=T, flag=s}}) ->
|
||||
contains_date2(#flatzone{std_from=From, std_to=To}, {Dt,#tztime{time=T, flag=s}}) ->
|
||||
Date={Dt, T},
|
||||
ezic_date:compare(From, Date) andalso ezic_date:compare(Date, To);
|
||||
|
||||
contains_date2(FlatZone=#flatzone{wall_from=From, wall_to=To}, {Dt,#tztime{time=T, flag=F}})
|
||||
contains_date2(#flatzone{wall_from=From, wall_to=To}, {Dt,#tztime{time=T, flag=F}})
|
||||
when F=:=w; F=:=undefined ->
|
||||
Date={Dt, T},
|
||||
ezic_date:compare(From, Date) andalso ezic_date:compare(Date, To).
|
||||
@@ -141,7 +140,7 @@ flatten_zone_set(FromTimeStub=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
|
||||
|
||||
|
||||
%% we gather all rules that _may_ apply
|
||||
Rules= ets:select(rule, [{#rule{name=RuleName, _='_'}, [], ['$_']}]),
|
||||
Rules= ezic_db:rules(RuleName),
|
||||
|
||||
|
||||
?debugVal(FromTime),
|
||||
|
||||
@@ -58,7 +58,7 @@ years(#rule{from=From, to=To}) ->
|
||||
%% calculation stops after a fixed year, configurable above.
|
||||
years_after(Y, {F,M}) when M=:=max; M=:=maximum ->
|
||||
{erlang:max(Y,F), M};
|
||||
years_after(Y, {From, To}) when Y > To ->
|
||||
years_after(Y, {_From, To}) when Y > To ->
|
||||
none;
|
||||
years_after(Y, {From, To}) ->
|
||||
{erlang:max(Y,From), To}.
|
||||
|
||||
@@ -40,7 +40,7 @@ start_link(_) ->
|
||||
%% specifications.
|
||||
%%--------------------------------------------------------------------
|
||||
init(_) ->
|
||||
EzicDb = {ezic_db_ets,{ezic_db_ets, start_link, []},
|
||||
EzicDb = {ezic_db,{ezic_db, start_link, []},
|
||||
permanent,2000,worker,[ezic_db_ets]},
|
||||
{ok,{{one_for_all,3,30}, [EzicDb]}}.
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
-module(ezic_zone).
|
||||
-include("include/ezic.hrl").
|
||||
-define(NODEBUG, true).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-export([
|
||||
@@ -42,7 +41,7 @@ current(TzName) ->
|
||||
current_as_of_utc(erlang:universaltime(), TzName).
|
||||
|
||||
current_as_of_utc(UTCDatetime, TzName) ->
|
||||
Zones= ezic_db_ets:zones(TzName),
|
||||
Zones= ezic_db:zones(TzName),
|
||||
get_zone_utc(UTCDatetime, Zones).
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user