diff --git a/c_src/esqlite3_nif.c b/c_src/esqlite3_nif.c index 767500c..151d1b7 100644 --- a/c_src/esqlite3_nif.c +++ b/c_src/esqlite3_nif.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Maas-Maarten Zeeman + * Copyright 2011, 2012 Maas-Maarten Zeeman * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,6 @@ #include #include -#include /* for debugging */ - #include "queue.h" #include "sqlite3.h" diff --git a/src/esqlite3.erl b/src/esqlite3.erl index 83d793d..22c8fa3 100644 --- a/src/esqlite3.erl +++ b/src/esqlite3.erl @@ -1,9 +1,9 @@ %% @author Maas-Maarten Zeeman -%% @copyright 2011 Maas-Maarten Zeeman +%% @copyright 2011, 2012 Maas-Maarten Zeeman %% @doc Erlang API for sqlite3 databases -%% Copyright 2011 Maas-Maarten Zeeman +%% Copyright 2011, 2012 Maas-Maarten Zeeman %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -33,17 +33,24 @@ -export([q/2, q/3, map/3, foreach/3]). --define(DEFAULT_TIMEOUT, infinity). +-define(DEFAULT_TIMEOUT, 5000). + +%% +-type connection() :: tuple(). +-type statement() :: term(). +-type sql() :: iolist(). %% @doc Opens a sqlite3 database mentioned in Filename. %% -%% @spec open(string()) -> {ok, connection()} | {error, error_message()} +-spec open(FileName) -> {ok, connection()} | {error, _} when + FileName :: string(). open(Filename) -> open(Filename, ?DEFAULT_TIMEOUT). %% @doc Open a database connection %% -%% @spec open(string(), timeout()) -> {ok, connection()} | {error, error_message()} +-spec open(Filename, timeout()) -> {ok, connection()} | {error, _} when + Filename :: string(). open(Filename, Timeout) -> {ok, Connection} = esqlite3_nif:start(), @@ -51,51 +58,66 @@ open(Filename, Timeout) -> ok = esqlite3_nif:open(Connection, Ref, self(), Filename), case receive_answer(Ref, Timeout) of ok -> - {ok, Connection}; + {ok, {connection, make_ref(), Connection}}; {error, _Msg}=Error -> Error end. -%% @doc Execute a sql statement, returns a list with tuples. +%% @doc Execute a sql statement, returns a list with tuples. +-spec q(sql(), connection()) -> list(tuple()). q(Sql, Connection) -> q(Sql, [], Connection). %% @doc Execute statement, bind args and return a list with tuples as result. +-spec q(sql(), list(), connection()) -> list(tuple()). q(Sql, [], Connection) -> case prepare(Sql, Connection) of {ok, Statement} -> fetchall(Statement); - {error, _Msg}=E -> - throw(E) + {error, _Msg}=Error -> + throw(Error) end; q(Sql, Args, Connection) -> case prepare(Sql, Connection) of {ok, Statement} -> ok = bind(Statement, Args), fetchall(Statement); - {error, _Msg}=E -> - throw(E) + {error, _Msg}=Error -> + throw(Error) end. -%% +%% @doc +-spec map(F, sql(), connection()) -> list(Type) when + F :: fun((Row) -> Type) | fun((ColumnNames, Row) -> Type), + Row :: tuple(), + ColumnNames :: tuple(), + Type :: any(). map(F, Sql, Connection) -> case prepare(Sql, Connection) of {ok, Statement} -> map_s(F, Statement); - {error, _Msg}=E -> - throw(E) + {error, _Msg}=Error -> + throw(Error) end. -%% +%% @doc +-spec foreach(F, sql(), connection()) -> ok when + F :: fun((Row) -> any()) | fun((ColumnNames, Row) -> any()), + Row :: tuple(), + ColumnNames :: tuple(). foreach(F, Sql, Connection) -> case prepare(Sql, Connection) of {ok, Statement} -> foreach_s(F, Statement); - {error, _Msg}=E -> - throw(E) + {error, _Msg}=Error -> + throw(Error) end. %% +-spec foreach_s(F, statement()) -> ok when + F :: fun((Row) -> any()) | fun((ColumnNames, Row) -> any()), + Row :: tuple(), + ColumnNames :: tuple(). foreach_s(F, Statement) when is_function(F, 1) -> case try_step(Statement, 0) of '$done' -> ok; @@ -113,6 +135,11 @@ foreach_s(F, Statement) when is_function(F, 2) -> end. %% +-spec map_s(F, statement()) -> list(Type) when + F :: fun((Row) -> Type) | fun((ColumnNames, Row) -> Type), + Row :: tuple(), + ColumnNames :: tuple(), + Type :: term(). map_s(F, Statement) when is_function(F, 1) -> case try_step(Statement, 0) of '$done' -> []; @@ -128,13 +155,15 @@ map_s(F, Statement) when is_function(F, 2) -> end. %% +-spec fetchone(statement()) -> tuple(). fetchone(Statement) -> case try_step(Statement, 0) of '$done' -> ok; {row, Row} -> Row end. -%% +%% +-spec fetchall(statement()) -> list(tuple()). fetchall(Statement) -> case try_step(Statement, 0) of '$done' -> @@ -144,6 +173,7 @@ fetchall(Statement) -> end. %% Try the step, when the database is busy, +-spec try_step(statement(), non_neg_integer()) -> term(). try_step(_Statement, Tries) when Tries > 5 -> throw(too_many_tries); try_step(Statement, Tries) -> @@ -164,7 +194,7 @@ exec(Sql, Connection) -> %% @doc Execute %% %% @spec exec(iolist(), connection(), timeout()) -> integer() | {error, error_message()} -exec(Sql, Connection, Timeout) -> +exec(Sql, {connection, _Ref, Connection}, Timeout) -> Ref = make_ref(), ok = esqlite3_nif:exec(Connection, Ref, self(), add_eos(Sql)), receive_answer(Ref, Timeout). @@ -178,7 +208,7 @@ prepare(Sql, Connection) -> %% @doc %% %% @spec(iolist(), connection(), timeout()) -> {ok, prepared_statement()} | {error, error_message()} -prepare(Sql, Connection, Timeout) -> +prepare(Sql, {connection, _Ref, Connection}, Timeout) -> Ref = make_ref(), ok = esqlite3_nif:prepare(Connection, Ref, self(), add_eos(Sql)), receive_answer(Ref, Timeout). @@ -224,13 +254,15 @@ column_names(Stmt, Timeout) -> %% @doc Close the database %% %% @spec close(connection()) -> ok | {error, error_message()} +-spec close(connection()) -> ok | {error, _}. close(Connection) -> close(Connection, ?DEFAULT_TIMEOUT). %% @doc Close the database %% %% @spec close(connection(), integer()) -> ok | {error, error_message()} -close(Connection, Timeout) -> +-spec close(connection(), timeout()) -> ok | {error, _}. +close({connection, _Ref, Connection}, Timeout) -> Ref = make_ref(), ok = esqlite3_nif:close(Connection, Ref, self()), receive_answer(Ref, Timeout). @@ -246,8 +278,3 @@ receive_answer(Ref, Timeout) -> after Timeout -> throw({error, timeout, Ref}) end. - - - - - diff --git a/src/esqlite3_nif.erl b/src/esqlite3_nif.erl index 3f1c37b..794a326 100644 --- a/src/esqlite3_nif.erl +++ b/src/esqlite3_nif.erl @@ -1,9 +1,9 @@ %% @author Maas-Maarten Zeeman -%% @copyright 2011 Maas-Maarten Zeeman +%% @copyright 2011, 2012 Maas-Maarten Zeeman %% @doc Low level erlang API for sqlite3 databases -%% Copyright 2011 Maas-Maarten Zeeman +%% Copyright 2011, 2012 Maas-Maarten Zeeman %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License.