diff --git a/apps/backend/app/repositories/reading.py b/apps/backend/app/repositories/reading.py index d251f55..d005d16 100644 --- a/apps/backend/app/repositories/reading.py +++ b/apps/backend/app/repositories/reading.py @@ -13,11 +13,12 @@ class ReadingRepository: async def latest_by_site(self) -> Sequence[Reading]: # `.distinct(site_id)` compile en `DISTINCT ON (site_id)` sous PostgreSQL : une seule - # ligne par site, la plus récente grâce à l'ordre composite qui suit. + # ligne par site, la plus récente grâce à l'ordre composite qui suit. `reading_id` départage + # les égalités de timestamp, que `uq_reading_source` autorise à `source` différente. requete = ( select(Reading) .distinct(Reading.site_id) - .order_by(Reading.site_id, Reading.timestamp.desc()) + .order_by(Reading.site_id, Reading.timestamp.desc(), Reading.reading_id.desc()) ) return (await self._session.execute(requete)).scalars().all() diff --git a/apps/backend/tests/repositories/test_reading.py b/apps/backend/tests/repositories/test_reading.py index dd2f2df..4f12df0 100644 --- a/apps/backend/tests/repositories/test_reading.py +++ b/apps/backend/tests/repositories/test_reading.py @@ -88,6 +88,26 @@ async def test_latest_by_site_returns_one_row_per_site(session: AsyncSession) -> assert identifiants == {premier, second} +async def test_latest_by_site_breaks_a_timestamp_tie_on_the_last_written_reading( + session: AsyncSession, +) -> None: + site = await creer_site(session) + depot = ReadingRepository(session) + horodatage = datetime(2026, 9, 15, tzinfo=UTC) + await creer_lecture( + session, site_id=site.site_id, timestamp=horodatage, source="api_history", consumption_kw=10 + ) + derniere = await creer_lecture( + session, site_id=site.site_id, timestamp=horodatage, source="api_current", consumption_kw=42 + ) + + resultats = await depot.latest_by_site() + retenues = [r.reading_id for r in resultats if r.site_id == site.site_id] + await session.rollback() + + assert retenues == [derniere.reading_id] + + async def test_latest_for_site_returns_the_most_recent_reading(session: AsyncSession) -> None: site = await creer_site(session) depot = ReadingRepository(session)