mypy black ruff
Tests / test (push) Successful in 11s
Tests / lint (push) Successful in 11s

This commit is contained in:
2026-10-16 22:51:11 +02:00
parent 553e1a4c83
commit 1fcaec8daf
10 changed files with 275 additions and 164 deletions
+98 -61
View File
@@ -5,9 +5,10 @@ The upsert function has two paths:
2. Row doesn't exist -> insert new row
These tests cover the update path (lines 25-26).
NOTE: MYPY errors suppressed for test fixtures - see AGENTS.md for type checking notes.
"""
from sqlalchemy import select
from sqlalchemy.orm import Session
from src.db_utils import upsert
@@ -18,117 +19,139 @@ class TestUpsertUpdatePath:
def test_upsert_updates_existing_row(self, db_session: Session):
"""Test that upsert updates an existing row when do_update=True."""
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class TestModel(Base):
__tablename__ = "test_model"
id: int = Column(Integer, primary_key=True, autoincrement=True)
name: str = Column(String(100), nullable=False)
value: str = Column(String(50), nullable=False)
Base.metadata.create_all(db_session.get_bind())
# Create and insert a row
initial = TestModel(name="initial", value="old_value")
db_session.add(initial)
db_session.commit()
# Verify it was inserted
result = db_session.query(TestModel).filter_by(name="initial").one() # type: ignore
result = db_session.query(TestModel).filter_by(name="initial").one()
assert result.value == "old_value"
def test_upsert_skips_update_when_do_update_false(self, db_session: Session):
"""Test that upsert doesn't modify existing row when do_update=False."""
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class TestModel(Base):
__tablename__ = "test_model_2"
id: int = Column(Integer, primary_key=True, autoincrement=True)
name: str = Column(String(100), nullable=False)
value: str = Column(String(50), nullable=False)
Base.metadata.create_all(db_session.get_bind())
# Create and insert a row
initial = TestModel(name="skip_update", value="original")
db_session.add(initial)
db_session.commit()
# Upsert with do_update=False should not modify existing row
same_row = TestModel(name="skip_update", value="should_not_change")
result = upsert(db_session, TestModel, {"name": "skip_update"}, same_row.__dict__,
do_update=False, do_commit=True)
result = upsert(
db_session,
TestModel,
{"name": "skip_update"},
same_row.__dict__,
do_update=False,
do_commit=True,
)
# The row should still have original values
assert result.value == "original"
def test_upsert_updates_and_returns_existing(self, db_session: Session):
"""Test that upsert returns the existing (now updated) row when do_update=True."""
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class TestModel(Base):
__tablename__ = "test_model_3"
id: int = Column(Integer, primary_key=True, autoincrement=True)
name: str = Column(String(100), nullable=False)
value: str = Column(String(50), nullable=False)
Base.metadata.create_all(db_session.get_bind())
# Create and insert a row
initial = TestModel(name="update_test", value="old")
db_session.add(initial)
db_session.commit()
# Upsert with do_update=True should update and return the same object
new_values = TestModel(name="update_test", value="new_value")
result = upsert(db_session, TestModel, {"name": "update_test"}, new_values.__dict__,
do_update=True, do_commit=True)
result = upsert(
db_session,
TestModel,
{"name": "update_test"},
new_values.__dict__,
do_update=True,
do_commit=True,
)
# Result should be the same row (not a new one)
assert result is not None
# Should have updated values
assert result.value == "new_value"
def test_upsert_returns_updated_row_by_value_when_not_same_object(self, db_session: Session):
def test_upsert_returns_updated_row_by_value_when_not_same_object(
self, db_session: Session
):
"""Test update path when the returned row is same by identity (session cache)."""
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class TestModel(Base):
__tablename__ = "test_model_4"
id: int = Column(Integer, primary_key=True, autoincrement=True)
name: str = Column(String(100), nullable=False)
value: str = Column(String(50), nullable=False)
Base.metadata.create_all(db_session.get_bind())
# Create and insert a row
initial = TestModel(name="identity_test", value="initial")
db_session.add(initial)
db_session.commit()
# Get the row from DB again (fresh load)
before_update = db_session.query(TestModel).filter_by(name="identity_test").one() # type: ignore
before_update = (
db_session.query(TestModel).filter_by(name="identity_test").one()
)
# Now upsert should return same object due to session cache + identity map
new_values = TestModel(name="identity_test", value="updated")
result = upsert(db_session, TestModel, {"name": "identity_test"}, new_values.__dict__,
do_update=True, do_commit=False) # don't commit yet
result = upsert(
db_session,
TestModel,
{"name": "identity_test"},
new_values.__dict__,
do_update=True,
do_commit=False,
) # don't commit yet
# Should be same identity due to session cache
assert result is before_update
assert result.value == "updated"
@@ -139,31 +162,39 @@ class TestUpsertUpdateEdgeCases:
def test_upsert_partial_update(self, db_session: Session):
"""Test that only specified fields are updated."""
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class TestModel(Base):
__tablename__ = "test_model_5"
id: int = Column(Integer, primary_key=True, autoincrement=True)
name: str = Column(String(100), nullable=False)
value: str = Column(String(50), nullable=False)
extra: str = Column(String(50), nullable=False)
Base.metadata.create_all(db_session.get_bind())
# Create and insert a row with all fields
initial = TestModel(name="partial", value="original_value", extra="extra_original")
initial = TestModel(
name="partial", value="original_value", extra="extra_original"
)
db_session.add(initial)
db_session.commit()
# Create new values with only some fields set (note: we skip 'extra' field)
partial_update = TestModel(name="partial", value="new_value", extra=None)
result = upsert(db_session, TestModel, {"name": "partial"}, partial_update.__dict__,
do_update=True, do_commit=True)
result = upsert(
db_session,
TestModel,
{"name": "partial"},
partial_update.__dict__,
do_update=True,
do_commit=True,
)
# value should be updated since it was in the dict
assert result.value == "new_value"
# extra field handling depends on what's in the __dict__
@@ -174,28 +205,34 @@ class TestUpsertUpdateEmptyDict:
def test_upsert_with_empty_update_dict(self, db_session: Session):
"""Test upsert with empty parameters_new dict - should still work if existing found."""
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class TestModel(Base):
__tablename__ = "test_model_6"
id: int = Column(Integer, primary_key=True, autoincrement=True)
name: str = Column(String(100), nullable=False)
value: str = Column(String(50), nullable=False)
Base.metadata.create_all(db_session.get_bind())
# Create and insert a row
initial = TestModel(name="empty_dict", value="test")
db_session.add(initial)
db_session.commit()
# Try to upsert with empty new parameters (edge case)
result = upsert(db_session, TestModel, {"name": "empty_dict"}, {},
do_update=True, do_commit=False)
result = upsert(
db_session,
TestModel,
{"name": "empty_dict"},
{},
do_update=True,
do_commit=False,
)
# Should return the existing row unchanged
assert result is not None
assert result.name == "empty_dict"