Added map and foreach support on queries

This commit is contained in:
Maas-Maarten Zeeman
2011-11-21 08:49:29 +01:00
parent d4e76607f0
commit e9eff0f31b
2 changed files with 109 additions and 122 deletions

View File

@@ -28,6 +28,8 @@
bind/2, bind/3,
close/1, close/2]).
-export([q/2, map/3, foreach/3]).
-define(DEFAULT_TIMEOUT, infinity).
%% @doc Opens a sqlite3 database mentioned in Filename.
@@ -40,43 +42,95 @@ open(Filename) ->
%%
%% @spec open(string(), timeout()) -> {ok, connection()} | {error, error_message()}
open(Filename, Timeout) ->
{ok, Db} = esqlite3_nif:start(),
{ok, Connection} = esqlite3_nif:start(),
Ref = make_ref(),
ok = esqlite3_nif:open(Db, Ref, self(), Filename),
ok = esqlite3_nif:open(Connection, Ref, self(), Filename),
case receive_answer(Ref, Timeout) of
ok ->
{ok, Db};
{ok, Connection};
Other ->
{error, Other}
end.
%% @doc Execute Sql statement
%% @doc Execute a sql statement, returns a list with tuples.
q(Sql, Connection) ->
{ok, Statement} = prepare(Sql, Connection),
do_steps(Statement).
%%
map(F, Sql, Connection) ->
{ok, Statement} = prepare(Sql, Connection),
map_s(F, Statement).
%%
foreach(F, Sql, Connection) ->
{ok, Statement} = prepare(Sql, Connection),
foreach_s(F, Statement).
%%
%% @spec exec(connection(), iolist()) -> integer() | {error, error_message()}
exec(Db, Sql) ->
exec(Db, Sql, ?DEFAULT_TIMEOUT).
foreach_s(F, Statement) ->
case try_step(Statement, 0) of
'$done' -> ok;
Row when is_tuple(Row) ->
F(Row),
foreach_s(F, Statement)
end.
%%
map_s(F, Statement) ->
case try_step(Statement, 0) of
'$done' ->
[];
Row ->
[F(Row) | map_s(F, Statement)]
end.
%%
do_steps(Statement) ->
case try_step(Statement, 0) of
'$done' ->
[];
Row when is_tuple(Row) ->
[Row | do_steps(Statement)]
end.
try_step(_Statement, Tries) when Tries > 5 ->
throw(too_many_tries);
try_step(Statement, Tries) ->
case esqlite3:step(Statement) of
'$busy' ->
try_step(Statement, Tries + 1);
Something ->
Something
end.
%% @doc Execute Sql statement, returns the number of affected rows.
%%
%% @spec exec(iolist(), connection()) -> integer() | {error, error_message()}
exec(Sql, Connection) ->
exec(Sql, Connection, ?DEFAULT_TIMEOUT).
%% @doc Execute
%%
%% @spec exec(connection(), iolist(), timeout()) -> integer() | {error, error_message()}
exec(Db, Sql, Timeout) ->
%% @spec exec(iolist(), connection(), timeout()) -> integer() | {error, error_message()}
exec(Sql, Connection, Timeout) ->
Ref = make_ref(),
ok = esqlite3_nif:exec(Db, Ref, self(), add_eos(Sql)),
ok = esqlite3_nif:exec(Connection, Ref, self(), add_eos(Sql)),
receive_answer(Ref, Timeout).
%% @doc Prepare a statement
%%
%% @spec prepare(connection(), iolist()) -> {ok, prepared_statement()} | {error, error_message()}
prepare(Db, Sql) ->
prepare(Db, Sql, ?DEFAULT_TIMEOUT).
%% @spec prepare(iolost(), connection()) -> {ok, prepared_statement()} | {error, error_message()}
prepare(Sql, Connection) ->
prepare(Sql, Connection, ?DEFAULT_TIMEOUT).
%% @doc
%%
%% @spec(connection(), iolist(), timeout()) -> {ok, prepared_statement()} | {error, error_message()}
prepare(Db, Sql, Timeout) ->
%% @spec(iolist(), connection(), timeout()) -> {ok, prepared_statement()} | {error, error_message()}
prepare(Sql, Connection, Timeout) ->
Ref = make_ref(),
ok = esqlite3_nif:prepare(Db, Ref, self(), add_eos(Sql)),
ok = esqlite3_nif:prepare(Connection, Ref, self(), add_eos(Sql)),
receive_answer(Ref, Timeout).
%% @doc Step
@@ -110,21 +164,20 @@ bind(Stmt, Args, Timeout) ->
%% @doc Close the database
%%
%% @spec close(connection()) -> ok | {error, error_message()}
close(Db) ->
close(Db, ?DEFAULT_TIMEOUT).
close(Connection) ->
close(Connection, ?DEFAULT_TIMEOUT).
%% @doc Close the database
%%
%% @spec close(connection(), integer()) -> ok | {error, error_message()}
close(Db, Timeout) ->
close(Connection, Timeout) ->
Ref = make_ref(),
ok = esqlite3_nif:close(Db, Ref, self()),
ok = esqlite3_nif:close(Connection, Ref, self()),
receive_answer(Ref, Timeout).
%% Internal functions
add_eos(String) when is_list(String) ->
[String, 0].
add_eos(IoList) ->
[IoList, 0].
receive_answer(Ref, Timeout) ->
receive