sqlite-utils/tests/test_mutator_transactions.py
2026-08-11 22:45:00 -07:00

154 lines
3.6 KiB
Python

import pytest
from sqlite_utils import Database
from sqlite_utils.utils import sqlite3
BASELINE_ROWS = [(1, "one"), (2, "two")]
def insert(table):
table.insert({"id": 3, "value": "three"}, pk="id")
def insert_all(table):
table.insert_all(
[
{"id": 3, "value": "three"},
{"id": 4, "value": "four"},
],
pk="id",
batch_size=1,
)
def upsert(table):
table.upsert({"id": 2, "value": "TWO"}, pk="id")
def upsert_all(table):
table.upsert_all(
[
{"id": 2, "value": "TWO"},
{"id": 3, "value": "three"},
],
pk="id",
batch_size=1,
)
def update(table):
table.update(2, {"value": "TWO"})
def delete(table):
table.delete(2)
def delete_where(table):
table.delete_where("id > ?", [1])
MUTATOR_CASES = (
pytest.param(
insert,
[(1, "one"), (2, "two"), (3, "three")],
id="insert",
),
pytest.param(
insert_all,
[(1, "one"), (2, "two"), (3, "three"), (4, "four")],
id="insert_all",
),
pytest.param(
upsert,
[(1, "one"), (2, "TWO")],
id="upsert",
),
pytest.param(
upsert_all,
[(1, "one"), (2, "TWO"), (3, "three")],
id="upsert_all",
),
pytest.param(
update,
[(1, "one"), (2, "TWO")],
id="update",
),
pytest.param(delete, [(1, "one")], id="delete"),
pytest.param(delete_where, [(1, "one")], id="delete_where"),
)
class RollbackTest(Exception):
pass
def seed_database(path):
conn = sqlite3.connect(str(path))
try:
conn.execute("create table items (id integer primary key, value text)")
conn.executemany("insert into items values (?, ?)", BASELINE_ROWS)
conn.commit()
finally:
conn.close()
return Database(path)
def current_rows(db):
return db.conn.execute("select id, value from items order by id").fetchall()
def persisted_rows(path):
conn = sqlite3.connect(str(path))
try:
return conn.execute("select id, value from items order by id").fetchall()
finally:
conn.close()
@pytest.mark.parametrize("mutate,expected_rows", MUTATOR_CASES)
def test_mutator_commits_by_default(tmp_path, mutate, expected_rows):
path = tmp_path / "default.db"
db = seed_database(path)
assert not db.conn.in_transaction
mutate(db["items"])
assert current_rows(db) == expected_rows
assert not db.conn.in_transaction
db.close()
assert persisted_rows(path) == expected_rows
@pytest.mark.parametrize("mutate,expected_rows", MUTATOR_CASES)
def test_mutator_commits_with_outer_atomic(tmp_path, mutate, expected_rows):
path = tmp_path / "atomic.db"
db = seed_database(path)
with db.atomic():
assert db.conn.in_transaction
mutate(db["items"])
assert current_rows(db) == expected_rows
assert db.conn.in_transaction
assert current_rows(db) == expected_rows
assert not db.conn.in_transaction
db.close()
assert persisted_rows(path) == expected_rows
@pytest.mark.parametrize("mutate,expected_rows", MUTATOR_CASES)
def test_mutator_rolls_back_outer_atomic(tmp_path, mutate, expected_rows):
path = tmp_path / "rollback.db"
db = seed_database(path)
with pytest.raises(RollbackTest), db.atomic():
mutate(db["items"])
assert current_rows(db) == expected_rows
assert db.conn.in_transaction
raise RollbackTest
assert current_rows(db) == BASELINE_ROWS
assert not db.conn.in_transaction
db.close()
assert persisted_rows(path) == BASELINE_ROWS