Exploring a pluggable generic sql database api
This commit is contained in:
41
src/gen_db.erl
Normal file
41
src/gen_db.erl
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
%%
|
||||||
|
%% Generic database interface. Sort of...
|
||||||
|
%%
|
||||||
|
%% Inspired by python's db api
|
||||||
|
%%
|
||||||
|
|
||||||
|
-module(gen_db).
|
||||||
|
|
||||||
|
-export([behaviour_info/1]).
|
||||||
|
|
||||||
|
-export([open/2, execute/2, execute/3, close/1]).
|
||||||
|
|
||||||
|
behaviour_info(callbacks) ->
|
||||||
|
[{handle_open, 1},
|
||||||
|
{handle_execute, 3},
|
||||||
|
{handle_close, 1}];
|
||||||
|
behaviour_info(_Other) ->
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
-record(gen_connection, {module, connection}).
|
||||||
|
|
||||||
|
%% @doc Open a connection to a new database
|
||||||
|
%%
|
||||||
|
open(Module, ModuleArgs) ->
|
||||||
|
{ok, Conn} = Module:handle_open(ModuleArgs),
|
||||||
|
{ok, #gen_connection{module=Module, connection=Conn}}.
|
||||||
|
|
||||||
|
%% @doc Prepare and execute a database operation
|
||||||
|
%%
|
||||||
|
execute(Operation, Connection) ->
|
||||||
|
execute(Operation, [], Connection).
|
||||||
|
|
||||||
|
%% @doc Prepare and execute a database operation
|
||||||
|
%%
|
||||||
|
execute(Operation, Args, #gen_connection{module=Module, connection=Connection}) ->
|
||||||
|
Module:handle_execute(Operation, Args, Connection).
|
||||||
|
|
||||||
|
%% @doc Close a database connection.
|
||||||
|
%%
|
||||||
|
close(#gen_connection{module=Module, connection=Connection}) ->
|
||||||
|
Module:handle_close(Connection).
|
||||||
45
src/sqlite.erl
Normal file
45
src/sqlite.erl
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
-module(sqlite).
|
||||||
|
|
||||||
|
-behaviour(gen_db).
|
||||||
|
|
||||||
|
-export([handle_open/1, handle_execute/3, handle_close/1]).
|
||||||
|
|
||||||
|
%% @doc Open a database connection
|
||||||
|
%%
|
||||||
|
handle_open(DatabaseName) ->
|
||||||
|
esqlite:open(DatabaseName).
|
||||||
|
|
||||||
|
%% @doc Execute a query and return the results
|
||||||
|
%%
|
||||||
|
handle_execute(Operation, Args, Connection) ->
|
||||||
|
{ok, Stmt} = esqlite:prepare(Connection, Operation),
|
||||||
|
ok = esqlite:bind(Stmt, Args),
|
||||||
|
Answer = execute(Stmt),
|
||||||
|
%% TODO Finalize the statement.
|
||||||
|
Answer.
|
||||||
|
|
||||||
|
|
||||||
|
%% @doc Close the connection
|
||||||
|
%%
|
||||||
|
handle_close(Connection) ->
|
||||||
|
esqlite:close(Connection).
|
||||||
|
|
||||||
|
%% @doc
|
||||||
|
%%
|
||||||
|
execute(Statement) ->
|
||||||
|
execute(Statement, [], 0).
|
||||||
|
|
||||||
|
%% @doc
|
||||||
|
%%
|
||||||
|
execute(_Statement, _Acc, Tries) when Tries > 5 ->
|
||||||
|
throw(too_many_tries);
|
||||||
|
execute(Statement, Acc, Tries) ->
|
||||||
|
case esqlite:step(Statement) of
|
||||||
|
'$done' ->
|
||||||
|
lists:reverse(Acc);
|
||||||
|
'$busy' ->
|
||||||
|
timer:sleep(100), %% This is a bit lame... there is a trigger api for this.
|
||||||
|
execute(Statement, Acc, Tries + 1);
|
||||||
|
V when is_tuple(V) ->
|
||||||
|
execute(Statement, [V | Acc], 0)
|
||||||
|
end.
|
||||||
Reference in New Issue
Block a user