Skip to content

introduce default_transaction_mode option #308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion lib/exqlite/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ defmodule Exqlite.Connection do

defstruct [
:db,
:default_transaction_mode,
:directory,
:path,
:transaction_status,
Expand All @@ -55,9 +56,11 @@ defmodule Exqlite.Connection do
@type synchronous() :: :extra | :full | :normal | :off
@type auto_vacuum() :: :none | :full | :incremental
@type locking_mode() :: :normal | :exclusive
@type transaction_mode() :: :deferred | :immediate | :exclusive

@type connection_opt() ::
{:database, String.t()}
| {:default_transaction_mode, transaction_mode()}
| {:mode, Sqlite3.open_opt()}
| {:journal_mode, journal_mode()}
| {:temp_store, temp_store()}
Expand Down Expand Up @@ -91,6 +94,9 @@ defmodule Exqlite.Connection do

* `:database` - The path to the database. In memory is allowed. You can use
`:memory` or `":memory:"` to designate that.
* `:default_transaction_mode` - one of `deferred` (default), `immediate`,
or `exclusive`. If a mode is not specified in a call to `Repo.transaction/2`,
this will be the default transaction mode.
* `:mode` - use `:readwrite` to open the database for reading and writing
, `:readonly` to open it in read-only mode or `[:readonly | :readwrite, :nomutex]`
to open it with no mutex mode. `:readwrite` will also create
Expand Down Expand Up @@ -260,7 +266,10 @@ defmodule Exqlite.Connection do
# append level on the savepoint. Instead the rollbacks would just completely
# revert the issues when it may be desirable to fix something while in the
# transaction and then commit.
case Keyword.get(options, :mode, :deferred) do

mode = Keyword.get(options, :mode, state.default_transaction_mode)

case mode do
:deferred when transaction_status == :idle ->
handle_transaction(:begin, "BEGIN TRANSACTION", state)

Expand Down Expand Up @@ -549,6 +558,8 @@ defmodule Exqlite.Connection do
:ok <- load_extensions(db, options) do
state = %__MODULE__{
db: db,
default_transaction_mode:
Keyword.get(options, :default_transaction_mode, :deferred),
directory: directory,
path: database,
transaction_status: :idle,
Expand Down
45 changes: 45 additions & 0 deletions test/exqlite/integration_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,51 @@ defmodule Exqlite.IntegrationTest do
File.rm(path)
end

test "transaction handling with immediate default_transaction_mode" do
path = Temp.path!()

{:ok, conn1} =
Connection.connect(
database: path,
default_transaction_mode: :immediate,
journal_mode: :wal,
cache_size: -64_000,
temp_store: :memory
)

{:ok, _result, conn1} = Connection.handle_begin([], conn1)
assert conn1.transaction_status == :transaction
assert conn1.default_transaction_mode == :immediate
query = %Query{statement: "create table foo(id integer, val integer)"}
{:ok, _query, _result, conn1} = Connection.handle_execute(query, [], [], conn1)
{:ok, _result, conn1} = Connection.handle_rollback([], conn1)
assert conn1.transaction_status == :idle

File.rm(path)
end

test "transaction handling with default default_transaction_mode" do
path = Temp.path!()

{:ok, conn1} =
Connection.connect(
database: path,
journal_mode: :wal,
cache_size: -64_000,
temp_store: :memory
)

{:ok, _result, conn1} = Connection.handle_begin([], conn1)
assert conn1.transaction_status == :transaction
assert conn1.default_transaction_mode == :deferred
query = %Query{statement: "create table foo(id integer, val integer)"}
{:ok, _query, _result, conn1} = Connection.handle_execute(query, [], [], conn1)
{:ok, _result, conn1} = Connection.handle_rollback([], conn1)
assert conn1.transaction_status == :idle

File.rm(path)
end

test "exceeding timeout" do
path = Temp.path!()

Expand Down
Loading