Added map and foreach support on queries
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user