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

Commit 168c768

Browse files
the-kennyConnorRigby
authored andcommitted
Add Sqlitex.with_transaction and use it in Sqlitex.Server
1 parent ec34b3a commit 168c768

File tree

3 files changed

+56
-28
lines changed

3 files changed

+56
-28
lines changed

lib/sqlitex.ex

+24
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,33 @@ defmodule Sqlitex do
150150
exec(db, stmt, call_opts)
151151
end
152152

153+
@spec with_transaction(Sqlitex.connection, (Sqlitex.connection -> any()), Keyword.t) :: any
154+
def with_transaction(db, fun, opts \\ []) do
155+
with :ok <- exec(db, "begin", opts),
156+
{:ok, result} <- apply_rescueing(fun, [db]),
157+
:ok <- exec(db, "commit", opts)
158+
do
159+
{:ok, result}
160+
else
161+
err ->
162+
:ok = exec(db, "rollback")
163+
err
164+
end
165+
end
166+
153167
if Version.compare(System.version, "1.3.0") == :lt do
154168
defp string_to_charlist(string), do: String.to_char_list(string)
155169
else
156170
defp string_to_charlist(string), do: String.to_charlist(string)
157171
end
172+
173+
## Private Helpers
174+
175+
defp apply_rescueing(fun, args) do
176+
try do
177+
{:ok, apply(fun, args)}
178+
rescue
179+
error -> {:error, error}
180+
end
181+
end
158182
end

lib/sqlitex/server.ex

+5-28
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,8 @@ defmodule Sqlitex.Server do
120120
end
121121

122122
def handle_call({:with_transaction, fun}, _from, {db, stmt_cache, timeout}) do
123-
with :ok <- Sqlitex.exec(db, "begin"),
124-
{:ok, result} <- apply_rescueing(fun, [db]),
125-
:ok <- Sqlitex.exec(db, "commit")
126-
do
127-
{:reply, result, {db, stmt_cache, timeout}}
128-
else
129-
err ->
130-
:ok = Sqlitex.exec(db, "rollback")
131-
{:reply, err, {db, stmt_cache, timeout}}
132-
end
123+
result = Sqlitex.with_transaction(db, fun)
124+
{:reply, result, {db, stmt_cache, timeout}}
133125
end
134126

135127
def handle_cast(:stop, {db, stmt_cache, config}) do
@@ -209,20 +201,13 @@ defmodule Sqlitex.Server do
209201
Runs `fun` inside a transaction. If `fun` returns without raising an exception,
210202
the transaction will be commited via `commit`. Otherwise, `rollback` will be called.
211203
212-
Statements are executed in the server process and are guaranteed to get executed
213-
sequentially without any interleaved statements from other processes.
214-
215-
It's important to use `Sqlitex.exec`, `Sqlitex.query`, ... instead of
216-
`Sqlitex.Server.exec`, ... inside the transaction as the `db` arg to `fun` is of
217-
type `Sqlitex.connection`.
218-
219204
## Examples
220-
iex> {:ok, s} = Sqlitex.Server.start_link(':memory:')
221-
iex> Sqlitex.Server.with_transaction(s, fn(db) ->
205+
iex> {:ok, db} = Sqlitex.open(":memory:")
206+
iex> Sqlitex.with_transaction(db, fn(db) ->
222207
...> Sqlitex.exec(db, "create table foo(id integer)")
223208
...> Sqlitex.exec(db, "insert into foo (id) values(42)")
224209
...> end)
225-
iex> Sqlitex.Server.query(s, "select * from foo")
210+
iex> Sqlitex.query(db, "select * from foo")
226211
{:ok, [[{:id, 42}]]}
227212
"""
228213
@spec with_transaction(pid(), (Sqlitex.connection -> any()), Keyword.t) :: any
@@ -254,12 +239,4 @@ defmodule Sqlitex.Server do
254239
end
255240

256241
defp timeout(kwopts), do: Keyword.get(kwopts, :timeout, 5000)
257-
258-
defp apply_rescueing(fun, args) do
259-
try do
260-
{:ok, apply(fun, args)}
261-
rescue
262-
error -> {:error, error}
263-
end
264-
end
265242
end

test/sqlitex_test.exs

+27
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,31 @@ defmodule Sqlitex.Test do
250250
assert row[:b] == nil
251251
assert row[:c] == nil
252252
end
253+
254+
test "with_transaction commit" do
255+
{:ok, db} = Sqlitex.open(":memory:")
256+
:ok = Sqlitex.exec(db, "create table foo(id integer)")
257+
258+
Sqlitex.with_transaction(db, fn db ->
259+
:ok = Sqlitex.exec(db, "insert into foo (id) values (42)")
260+
end)
261+
262+
assert Sqlitex.query(db, "select * from foo") == {:ok, [[{:id, 42}]]}
263+
end
264+
265+
test "with_transaction rollback" do
266+
{:ok, db} = Sqlitex.open(':memory:')
267+
:ok = Sqlitex.exec(db, "create table foo(id integer)")
268+
269+
try do
270+
Sqlitex.with_transaction(db, fn db ->
271+
:ok = Sqlitex.exec(db, "insert into foo (id) values (42)")
272+
raise "Error to roll back transaction"
273+
end)
274+
rescue
275+
_ -> nil
276+
end
277+
278+
assert Sqlitex.query(db, "select * from foo") == {:ok, []}
279+
end
253280
end

0 commit comments

Comments
 (0)