@@ -119,6 +119,19 @@ defmodule Sqlitex.Server do
119
119
{ :reply , result , { db , stmt_cache , config } }
120
120
end
121
121
122
+ 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
133
+ end
134
+
122
135
def handle_cast ( :stop , { db , stmt_cache , config } ) do
123
136
{ :stop , :normal , { db , stmt_cache , config } }
124
137
end
@@ -191,6 +204,32 @@ defmodule Sqlitex.Server do
191
204
GenServer . cast ( pid , :stop )
192
205
end
193
206
207
+
208
+ @ doc """
209
+ Runs `fun` inside a transaction. If `fun` returns without raising an exception,
210
+ the transaction will be commited via `commit`. Otherwise, `rollback` will be called.
211
+
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
+
219
+ ## Examples
220
+ iex> {:ok, s} = Sqlitex.Server.start_link(':memory:')
221
+ iex> Sqlitex.Server.with_transaction(s, fn(db) ->
222
+ ...> Sqlitex.exec(db, "create table foo(id integer)")
223
+ ...> Sqlitex.exec(db, "insert into foo (id) values(42)")
224
+ ...> end)
225
+ iex> Sqlitex.Server.query(s, "select * from foo")
226
+ {:ok, [[{:id, 42}]]}
227
+ """
228
+ @ spec with_transaction ( pid ( ) , ( Sqlitex . connection -> any ( ) ) , Keyword . t ) :: any
229
+ def with_transaction ( pid , fun , opts \\ [ ] ) do
230
+ GenServer . call ( pid , { :with_transaction , fun } , timeout ( opts ) )
231
+ end
232
+
194
233
## Helpers
195
234
196
235
defp query_impl ( sql , stmt_cache , opts ) do
@@ -213,4 +252,14 @@ defmodule Sqlitex.Server do
213
252
with { % Cache { } = new_cache , stmt } <- Cache . prepare ( stmt_cache , sql , opts ) ,
214
253
do: { :ok , % { columns: stmt . column_names , types: stmt . column_types } , new_cache }
215
254
end
255
+
256
+ 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
216
265
end
0 commit comments