11"""Integration tests for the SQLAlchemy Repository implementation using session-based fixtures."""
22
3+ import asyncio
34import datetime
45from collections .abc import Generator
56from typing import TYPE_CHECKING , Any , Literal , Optional , Union
@@ -339,14 +340,43 @@ async def test_repo_update_method(seeded_test_session_async: "tuple[AsyncSession
339340 # Get first author
340341 authors = await maybe_async (author_repo .list ())
341342 author = authors [0 ]
343+
342344 original_name = author .name
345+ original_created_at = author .created_at
346+ original_updated_at = author .updated_at
343347
344348 # Update the author
345349 author .name = "Updated Name"
346350 updated_author = await maybe_async (author_repo .update (author ))
347351
348352 assert updated_author .name == "Updated Name"
349353 assert updated_author .name != original_name
354+ assert updated_author .created_at == original_created_at
355+ assert updated_author .updated_at > original_updated_at
356+
357+
358+ async def test_service_update_with_dict_data_refreshes_timestamp (
359+ seeded_test_session_async : "tuple[AsyncSession, dict[str, type]]" ,
360+ frozen_datetime : "Coordinates" ,
361+ ) -> None :
362+ """Service update should refresh audit timestamps when supplied with dict payloads."""
363+ session , models = seeded_test_session_async
364+ author_service = get_service_from_session ((session , models ), "author" )
365+
366+ authors = await maybe_async (author_service .list ())
367+ author = authors [0 ]
368+
369+ original_created_at = author .created_at
370+ original_updated_at = author .updated_at
371+
372+ frozen_datetime .shift (datetime .timedelta (seconds = 5 ))
373+ update_payload = {"name" : "Dict Driven Update" }
374+
375+ updated_author = await maybe_async (author_service .update (update_payload , item_id = author .id ))
376+
377+ assert updated_author .name == "Dict Driven Update"
378+ assert updated_author .created_at == original_created_at
379+ assert updated_author .updated_at > original_updated_at
350380
351381
352382async def test_repo_update_many_method_stale_data_fix (
@@ -385,7 +415,7 @@ async def test_repo_update_many_method_stale_data_fix(
385415 # updated_at should be newer than before
386416 if updated_author .id == authors [0 ].id :
387417 assert updated_author .created_at == original_created_at
388- assert updated_author .updated_at >= original_updated_at
418+ assert updated_author .updated_at > original_updated_at
389419
390420
391421async def test_repo_update_many_mixed_types (seeded_test_session_async : "tuple[AsyncSession, dict[str, type]]" ) -> None :
@@ -498,11 +528,18 @@ async def test_service_update_method(seeded_test_session_async: "tuple[AsyncSess
498528 author = authors [0 ]
499529 author_id = author .id
500530
531+ original_name = author .name
532+ original_created_at = author .created_at
533+ original_updated_at = author .updated_at
534+
501535 # Update via service - correct parameter order is (data, item_id)
502- update_data = { "name" : " Service Updated Name"}
503- updated_author = await maybe_async (author_service .update (update_data , item_id = author_id ))
536+ author . name = " Service Updated Name"
537+ updated_author = await maybe_async (author_service .update (author , item_id = author_id ))
504538
505539 assert updated_author .name == "Service Updated Name"
540+ assert updated_author .name != original_name
541+ assert updated_author .created_at == original_created_at
542+ assert updated_author .updated_at > original_updated_at
506543
507544
508545async def test_service_delete_method (seeded_test_session_async : "tuple[AsyncSession, dict[str, type]]" ) -> None :
@@ -679,6 +716,10 @@ async def test_service_update_many_schema_types_github_535(
679716
680717 original_dob1 = author1 .dob
681718 original_dob2 = author2 .dob
719+ original_created_at1 = author1 .created_at
720+ original_created_at2 = author2 .created_at
721+ original_updated_at1 = author1 .updated_at
722+ original_updated_at2 = author2 .updated_at
682723
683724 # Get ID type from model for dynamic schema creation
684725 # For Pydantic compatibility, we need to map database-specific types to Python types
@@ -707,6 +748,9 @@ class AuthorUpdateMsgspecSchema(msgspec.Struct): # type: ignore[name-defined,mi
707748 AuthorUpdateMsgspecSchema (id = author2 .id , name = "Updated Author Two" ), # msgspec with UNSET dob
708749 ]
709750
751+ # Sleep to ensure timestamp difference for databases with lower precision
752+ await asyncio .sleep (1.1 )
753+
710754 # Update via service - should only update names, leave dobs unchanged
711755 updated_authors = await maybe_async (author_service .update_many (update_data ))
712756
@@ -720,9 +764,13 @@ class AuthorUpdateMsgspecSchema(msgspec.Struct): # type: ignore[name-defined,mi
720764 # Verify: names were updated, but dobs remain unchanged
721765 assert updated_author1 .name == "Updated Author One"
722766 assert updated_author1 .dob == original_dob1 # Should be unchanged
767+ assert updated_author1 .created_at == original_created_at1
768+ assert updated_author1 .updated_at > original_updated_at1
723769
724770 assert updated_author2 .name == "Updated Author Two"
725771 assert updated_author2 .dob == original_dob2 # Should be unchanged
772+ assert updated_author2 .created_at == original_created_at2
773+ assert updated_author2 .updated_at > original_updated_at2
726774
727775
728776async def test_repo_update_many_non_returning_backend_refresh (
0 commit comments