Skip to content
This repository was archived by the owner on Mar 19, 2021. It is now read-only.

Commit af7a286

Browse files
committed
Pass timeouts via keyword opts
Also changed to use :db_timeout as the key in most places, for brevity. Retained :esqlite3_timeout in the Application env.
1 parent 3f4f73e commit af7a286

File tree

7 files changed

+97
-85
lines changed

7 files changed

+97
-85
lines changed

lib/sqlitex.ex

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ defmodule Sqlitex do
3030
Sqlitex uses the Erlang library [esqlite](https://github.com/mmzeeman/esqlite)
3131
which accepts a timeout parameter for almost all interactions with the database.
3232
The default value for this timeout is 5000 ms. Many functions in Sqlitex accept
33-
a timeout parameter that is passed on to the esqlite calls and that also defaults
33+
a `:db_timeout` option that is passed on to the esqlite calls and that also defaults
3434
to 5000 ms. If required, this default value can be overridden globally with the
3535
following in your `config.exs`:
3636
@@ -40,29 +40,32 @@ defmodule Sqlitex do
4040
```
4141
"""
4242

43-
@esqlite3_timeout Application.get_env(:sqlitex, :esqlite3_timeout, 5_000)
43+
alias Sqlitex.Config
4444

45-
@spec close(connection, integer()) :: :ok
46-
def close(db, timeout \\ @esqlite3_timeout) do
45+
@spec close(connection, Keyword.t) :: :ok
46+
def close(db, opts \\ []) do
47+
timeout = Keyword.get(opts, :db_timeout, Config.esqlite3_timeout())
4748
:esqlite3.close(db, timeout)
4849
end
4950

50-
@spec open(charlist | String.t, integer()) :: {:ok, connection} | {:error, {atom, charlist}}
51-
def open(path, timeout \\ @esqlite3_timeout)
52-
def open(path, timeout) when is_binary(path), do: open(string_to_charlist(path), timeout)
53-
def open(path, timeout) do
51+
@spec open(charlist | String.t, Keyword.t) :: {:ok, connection} | {:error, {atom, charlist}}
52+
def open(path, opts \\ [])
53+
def open(path, opts) when is_binary(path), do: open(string_to_charlist(path), opts)
54+
def open(path, opts) do
55+
timeout = Keyword.get(opts, :db_timeout, Config.esqlite3_timeout())
5456
:esqlite3.open(path, timeout)
5557
end
5658

57-
def with_db(path, fun, timeout \\ @esqlite3_timeout) do
58-
{:ok, db} = open(path, timeout)
59+
def with_db(path, fun, opts \\ []) do
60+
{:ok, db} = open(path, opts)
5961
res = fun.(db)
60-
close(db, timeout)
62+
close(db, opts)
6163
res
6264
end
6365

64-
@spec exec(connection, string_or_charlist, integer()) :: :ok | sqlite_error
65-
def exec(db, sql, timeout \\ @esqlite3_timeout) do
66+
@spec exec(connection, string_or_charlist, Keyword.t) :: :ok | sqlite_error
67+
def exec(db, sql, opts \\ []) do
68+
timeout = Keyword.get(opts, :db_timeout, Config.esqlite3_timeout())
6669
:esqlite3.exec(sql, db, timeout)
6770
end
6871

@@ -89,9 +92,9 @@ defmodule Sqlitex do
8992
**id: :integer, name: {:text, [:not_null]}**
9093
9194
"""
92-
def create_table(db, name, table_opts \\ [], cols, timeout \\ @esqlite3_timeout) do
95+
def create_table(db, name, table_opts \\ [], cols, call_opts \\ []) do
9396
stmt = Sqlitex.SqlBuilder.create_table(name, table_opts, cols)
94-
exec(db, stmt, timeout)
97+
exec(db, stmt, call_opts)
9598
end
9699

97100
if Version.compare(System.version, "1.3.0") == :lt do

lib/sqlitex/config.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule Sqlitex.Config do
2+
@moduledoc false
3+
4+
def esqlite3_timeout do
5+
Application.get_env(:sqlitex, :esqlite3_timeout, default_esqlite3_timeout())
6+
end
7+
8+
def default_esqlite3_timeout, do: 5_000
9+
end

lib/sqlitex/query.ex

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ defmodule Sqlitex.Query do
1515
* `bind` - If your query has parameters in it, you should provide the options
1616
to bind as a list.
1717
* `into` - The collection to put results into. This defaults to a list.
18-
* `timeout` - The timeout (in ms) to apply to each of the underlying SQLite operations. Defaults
18+
* `db_timeout` - The timeout (in ms) to apply to each of the underlying SQLite operations. Defaults
1919
to 5000, or to `Application.get_env(:sqlitex, :esqlite3_timeout)` if set.
2020
2121
## Returns
@@ -30,7 +30,10 @@ defmodule Sqlitex.Query do
3030
@spec query(Sqlitex.connection, String.t | charlist) :: {:ok, [[]]} | {:error, term()}
3131
@spec query(Sqlitex.connection, String.t | charlist, [{atom, term}]) :: {:ok, [[]]} | {:error, term()}
3232
def query(db, sql, opts \\ []) do
33-
do_query(db, sql, opts, Keyword.get(opts, :timeout, nil))
33+
with {:ok, stmt} <- Statement.prepare(db, sql, opts),
34+
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, []), opts),
35+
{:ok, res} <- Statement.fetch_all(stmt, Keyword.get(opts, :into, [])),
36+
do: {:ok, res}
3437
end
3538

3639
@doc """
@@ -39,27 +42,14 @@ defmodule Sqlitex.Query do
3942
Returns the results otherwise.
4043
"""
4144
@spec query!(Sqlitex.connection, String.t | charlist) :: [[]]
42-
@spec query!(Sqlitex.connection, String.t | charlist, [bind: [], into: Enum.t, timeout: integer()]) :: [Enum.t]
45+
@spec query!(Sqlitex.connection, String.t | charlist, [bind: [], into: Enum.t, db_timeout: integer()]) :: [Enum.t]
4346
def query!(db, sql, opts \\ []) do
4447
case query(db, sql, opts) do
4548
{:error, reason} -> raise Sqlitex.QueryError, reason: reason
4649
{:ok, results} -> results
4750
end
4851
end
4952

50-
defp do_query(db, sql, opts, nil) do
51-
with {:ok, stmt} <- Statement.prepare(db, sql),
52-
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, [])),
53-
{:ok, res} <- Statement.fetch_all(stmt, Keyword.get(opts, :into, [])),
54-
do: {:ok, res}
55-
end
56-
defp do_query(db, sql, opts, timeout) do
57-
with {:ok, stmt} <- Statement.prepare(db, sql, timeout),
58-
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, []), timeout),
59-
{:ok, res} <- Statement.fetch_all(stmt, Keyword.get(opts, :into, [])),
60-
do: {:ok, res}
61-
end
62-
6353
@doc """
6454
Runs a query and returns the results as a list of rows each represented as
6555
a list of column values.
@@ -74,7 +64,7 @@ defmodule Sqlitex.Query do
7464
7565
* `bind` - If your query has parameters in it, you should provide the options
7666
to bind as a list.
77-
* `timeout` - The timeout (in ms) to apply to each of the underlying SQLite operations. Defaults
67+
* `db_timeout` - The timeout (in ms) to apply to each of the underlying SQLite operations. Defaults
7868
to 5000, or to `Application.get_env(:sqlitex, :esqlite3_timeout)` if set.
7969
8070
## Returns
@@ -83,9 +73,12 @@ defmodule Sqlitex.Query do
8373
"""
8474

8575
@spec query_rows(Sqlitex.connection, String.t | charlist) :: {:ok, %{}} | Sqlitex.sqlite_error
86-
@spec query_rows(Sqlitex.connection, String.t | charlist, [bind: [], timeout: integer()]) :: {:ok, %{}} | Sqlitex.sqlite_error
76+
@spec query_rows(Sqlitex.connection, String.t | charlist, [bind: [], db_timeout: integer()]) :: {:ok, %{}} | Sqlitex.sqlite_error
8777
def query_rows(db, sql, opts \\ []) do
88-
do_query_rows(db, sql, opts, Keyword.get(opts, :timeout, nil))
78+
with {:ok, stmt} <- Statement.prepare(db, sql, opts),
79+
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, []), opts),
80+
{:ok, rows} <- Statement.fetch_all(stmt, :raw_list),
81+
do: {:ok, %{rows: rows, columns: stmt.column_names, types: stmt.column_types}}
8982
end
9083

9184
@doc """
@@ -94,24 +87,11 @@ defmodule Sqlitex.Query do
9487
Returns the results otherwise.
9588
"""
9689
@spec query_rows!(Sqlitex.connection, String.t | charlist) :: %{}
97-
@spec query_rows!(Sqlitex.connection, String.t | charlist, [bind: [], timeout: integer()]) :: %{}
90+
@spec query_rows!(Sqlitex.connection, String.t | charlist, [bind: [], db_timeout: integer()]) :: %{}
9891
def query_rows!(db, sql, opts \\ []) do
9992
case query_rows(db, sql, opts) do
10093
{:error, reason} -> raise Sqlitex.QueryError, reason: reason
10194
{:ok, results} -> results
10295
end
10396
end
104-
105-
defp do_query_rows(db, sql, opts, nil) do
106-
with {:ok, stmt} <- Statement.prepare(db, sql),
107-
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, [])),
108-
{:ok, rows} <- Statement.fetch_all(stmt, :raw_list),
109-
do: {:ok, %{rows: rows, columns: stmt.column_names, types: stmt.column_types}}
110-
end
111-
defp do_query_rows(db, sql, opts, timeout) do
112-
with {:ok, stmt} <- Statement.prepare(db, sql, timeout),
113-
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, []), timeout),
114-
{:ok, rows} <- Statement.fetch_all(stmt, :raw_list),
115-
do: {:ok, %{rows: rows, columns: stmt.column_names, types: stmt.column_types}}
116-
end
11797
end

lib/sqlitex/server.ex

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ defmodule Sqlitex.Server do
4747

4848
alias Sqlitex.Statement
4949
alias Sqlitex.Server.StatementCache, as: Cache
50+
alias Sqlitex.Config
5051

5152
@doc """
5253
Starts a SQLite Server (GenServer) instance.
@@ -56,13 +57,13 @@ defmodule Sqlitex.Server do
5657
5758
- `stmt_cache_size: (positive_integer)` to override the default limit (20) of statements
5859
that are cached when calling `prepare/3`.
59-
- `esqlite3_timeout: (positive_integer)` to override `:esqlite3`'s default timeout of 5000 ms for
60+
- `db_timeout: (positive_integer)` to override `:esqlite3`'s default timeout of 5000 ms for
6061
interactions with the database. This can also be set in `config.exs` as
6162
`config :sqlitex, esqlite3_timeout: 5_000`.
6263
"""
6364
def start_link(db_path, opts \\ []) do
6465
stmt_cache_size = Keyword.get(opts, :stmt_cache_size, 20)
65-
timeout = Keyword.get(opts, :esqlite3_timeout, Application.get_env(:sqlitex, :esqlite3_timeout, 5_000))
66+
timeout = Keyword.get(opts, :db_timeout, Config.esqlite3_timeout())
6667
GenServer.start_link(__MODULE__, {db_path, stmt_cache_size, timeout}, opts)
6768
end
6869

@@ -71,14 +72,14 @@ defmodule Sqlitex.Server do
7172
def init({db_path, stmt_cache_size, timeout})
7273
when is_integer(stmt_cache_size) and stmt_cache_size > 0
7374
do
74-
case Sqlitex.open(db_path, timeout) do
75+
case Sqlitex.open(db_path, [db_timeout: timeout]) do
7576
{:ok, db} -> {:ok, {db, __MODULE__.StatementCache.new(db, stmt_cache_size), timeout}}
7677
{:error, reason} -> {:stop, reason}
7778
end
7879
end
7980

8081
def handle_call({:exec, sql}, _from, {db, stmt_cache, timeout}) do
81-
result = Sqlitex.exec(db, sql, timeout)
82+
result = Sqlitex.exec(db, sql, [db_timeout: timeout])
8283
{:reply, result, {db, stmt_cache, timeout}}
8384
end
8485

@@ -104,7 +105,7 @@ defmodule Sqlitex.Server do
104105
end
105106

106107
def handle_call({:create_table, name, table_opts, cols}, _from, {db, stmt_cache, timeout}) do
107-
result = Sqlitex.create_table(db, name, table_opts, cols, timeout)
108+
result = Sqlitex.create_table(db, name, table_opts, cols, [db_timeout: timeout])
108109
{:reply, result, {db, stmt_cache, timeout}}
109110
end
110111

@@ -163,24 +164,28 @@ defmodule Sqlitex.Server do
163164

164165
## Helpers
165166

166-
defp query_impl(sql, opts, stmt_cache, esqlite3_timeout) do
167-
with {%Cache{} = new_cache, stmt} <- Cache.prepare(stmt_cache, sql, esqlite3_timeout),
168-
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, []), esqlite3_timeout),
167+
defp query_impl(sql, opts, stmt_cache, db_timeout) do
168+
db_opts = [db_timeout: db_timeout]
169+
170+
with {%Cache{} = new_cache, stmt} <- Cache.prepare(stmt_cache, sql, db_opts),
171+
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, []), db_opts),
169172
{:ok, rows} <- Statement.fetch_all(stmt, Keyword.get(opts, :into, [])),
170173
do: {:ok, rows, new_cache}
171174
end
172175

173-
defp query_rows_impl(sql, opts, stmt_cache, esqlite3_timeout) do
174-
with {%Cache{} = new_cache, stmt} <- Cache.prepare(stmt_cache, sql, esqlite3_timeout),
175-
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, []), esqlite3_timeout),
176+
defp query_rows_impl(sql, opts, stmt_cache, db_timeout) do
177+
db_opts = [db_timeout: db_timeout]
178+
179+
with {%Cache{} = new_cache, stmt} <- Cache.prepare(stmt_cache, sql, db_opts),
180+
{:ok, stmt} <- Statement.bind_values(stmt, Keyword.get(opts, :bind, []), db_opts),
176181
{:ok, rows} <- Statement.fetch_all(stmt, :raw_list),
177182
do: {:ok,
178183
%{rows: rows, columns: stmt.column_names, types: stmt.column_types},
179184
new_cache}
180185
end
181186

182-
defp prepare_impl(sql, stmt_cache, esqlite3_timeout) do
183-
with {%Cache{} = new_cache, stmt} <- Cache.prepare(stmt_cache, sql, esqlite3_timeout),
187+
defp prepare_impl(sql, stmt_cache, db_timeout) do
188+
with {%Cache{} = new_cache, stmt} <- Cache.prepare(stmt_cache, sql, [db_timeout: db_timeout]),
184189
do: {:ok, %{columns: stmt.column_names, types: stmt.column_types}, new_cache}
185190
end
186191

lib/sqlitex/server/statement_cache.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ defmodule Sqlitex.Server.StatementCache do
2525
2626
Will return `{:error, reason}` if SQLite is unable to prepare the statement.
2727
"""
28-
def prepare(%__MODULE__{cached_stmts: cached_stmts} = cache, sql, timeout)
28+
def prepare(%__MODULE__{cached_stmts: cached_stmts} = cache, sql, opts \\ [])
2929
when is_binary(sql) and byte_size(sql) > 0
3030
do
3131
case Map.fetch(cached_stmts, sql) do
3232
{:ok, stmt} -> {update_cache_for_read(cache, sql), stmt}
33-
:error -> prepare_new_statement(cache, sql, timeout)
33+
:error -> prepare_new_statement(cache, sql, opts)
3434
end
3535
end
3636

37-
defp prepare_new_statement(%__MODULE__{db: db} = cache, sql, timeout) do
38-
case Sqlitex.Statement.prepare(db, sql, timeout) do
37+
defp prepare_new_statement(%__MODULE__{db: db} = cache, sql, opts \\ []) do
38+
case Sqlitex.Statement.prepare(db, sql, opts) do
3939
{:ok, prepared} ->
4040
cache = cache
4141
|> store_new_stmt(sql, prepared)

lib/sqlitex/statement.ex

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ defmodule Sqlitex.Statement do
7373
column_names: [],
7474
column_types: []
7575

76-
@esqlite3_timeout Application.get_env(:sqlitex, :esqlite3_timeout, 5_000)
76+
alias Sqlitex.Config
7777

7878
@doc """
7979
Prepare a Sqlitex.Statement
@@ -82,14 +82,19 @@ defmodule Sqlitex.Statement do
8282
8383
* `db` - The database to prepare the statement for.
8484
* `sql` - The SQL of the statement to prepare.
85-
* `timeout` - The time in ms allowed for the statement to run. Defaults to 5000, or the :esqlite3_timeout value in Application env.
85+
86+
Also accepts the following keyword options:
87+
88+
* `db_timeout` - The time in ms allowed for the statement to run. Defaults to 5000, or the :esqlite3_timeout value in Application env.
8689
8790
## Returns
8891
8992
* `{:ok, statement}` on success
9093
* See `:esqlite3.prepare` for errors.
9194
"""
92-
def prepare(db, sql, timeout \\ @esqlite3_timeout) do
95+
def prepare(db, sql, opts \\ []) do
96+
timeout = Keyword.get(opts, :db_timeout, Config.esqlite3_timeout)
97+
9398
with {:ok, stmt} <- do_prepare(db, sql, timeout),
9499
{:ok, stmt} <- get_column_names(stmt, timeout),
95100
{:ok, stmt} <- get_column_types(stmt, timeout),
@@ -102,8 +107,8 @@ defmodule Sqlitex.Statement do
102107
103108
Returns a new statement otherwise.
104109
"""
105-
def prepare!(db, sql, timeout \\ @esqlite3_timeout) do
106-
case prepare(db, sql, timeout) do
110+
def prepare!(db, sql, opts \\ []) do
111+
case prepare(db, sql, opts) do
107112
{:ok, statement} -> statement
108113
{:error, reason} -> raise Sqlitex.Statement.PrepareError, reason: reason
109114
end
@@ -116,7 +121,10 @@ defmodule Sqlitex.Statement do
116121
117122
* `statement` - The statement to bind values into.
118123
* `values` - A list of values to bind into the statement.
119-
* `timeout` - The time in ms allowed for the statement to run. Defaults to 5000, or the :esqlite3_timeout value in Application env.
124+
125+
Also accepts the following keyword options:
126+
127+
* `db_timeout` - The time in ms allowed for the statement to run. Defaults to 5000, or the :esqlite3_timeout value in Application env.
120128
121129
## Returns
122130
@@ -133,7 +141,9 @@ defmodule Sqlitex.Statement do
133141
* `datetime` - Converted into a string. See datetime_to_string
134142
* `%Decimal` - Converted into a number.
135143
"""
136-
def bind_values(statement, values, timeout \\ @esqlite3_timeout) do
144+
def bind_values(statement, values, opts \\ []) do
145+
timeout = Keyword.get(opts, :db_timeout, Config.esqlite3_timeout)
146+
137147
case :esqlite3.bind(statement.statement, translate_bindings(values), timeout) do
138148
{:error, _} = error -> error
139149
:ok -> {:ok, statement}
@@ -145,8 +155,8 @@ defmodule Sqlitex.Statement do
145155
146156
Returns the statement otherwise.
147157
"""
148-
def bind_values!(statement, values, timeout \\ @esqlite3_timeout) do
149-
case bind_values(statement, values, timeout) do
158+
def bind_values!(statement, values, opts \\ []) do
159+
case bind_values(statement, values, opts) do
150160
{:ok, statement} -> statement
151161
{:error, reason} -> raise Sqlitex.Statement.BindValuesError, reason: reason
152162
end
@@ -202,14 +212,19 @@ defmodule Sqlitex.Statement do
202212
## Parameters
203213
204214
* `statement` - The statement to run.
205-
* `timeout` - The time in ms allowed for the statement to run. Defaults to 5000, or the :esqlite3_timeout value in Application env.
215+
216+
Also accepts the following keyword options:
217+
218+
* `db_timeout` - The time in ms allowed for the statement to run. Defaults to 5000, or the :esqlite3_timeout value in Application env.
206219
207220
## Returns
208221
209222
* `:ok`
210223
* `{:error, error}`
211224
"""
212-
def exec(statement, timeout \\ @esqlite3_timeout) do
225+
def exec(statement, opts \\ []) do
226+
timeout = Keyword.get(opts, :db_timeout, Config.esqlite3_timeout)
227+
213228
case :esqlite3.step(statement.statement, timeout) do
214229
# esqlite3.step returns some odd values, so lets translate them:
215230
:"$done" -> :ok
@@ -223,8 +238,8 @@ defmodule Sqlitex.Statement do
223238
224239
Returns :ok otherwise.
225240
"""
226-
def exec!(statement, timeout \\ @esqlite3_timeout) do
227-
case exec(statement, timeout) do
241+
def exec!(statement, opts \\ []) do
242+
case exec(statement, opts) do
228243
:ok -> :ok
229244
{:error, reason} -> raise Sqlitex.Statement.ExecError, reason: reason
230245
end

0 commit comments

Comments
 (0)