fix: query when only 1 data per day, or 1 day selected

This commit is contained in:
Alexis Fourmaux 2026-05-10 13:17:58 +02:00
parent 5cef99d8d9
commit f127a4c34c
3 changed files with 34 additions and 14 deletions

View file

@ -1,4 +1,5 @@
from datetime import datetime from datetime import datetime
from dateutil.relativedelta import relativedelta
import psycopg2 import psycopg2
from psycopg2.extensions import connection from psycopg2.extensions import connection
@ -9,6 +10,14 @@ from domain.value_objects import Granularity
from ports.reading_query_repository import ReadingQueryRepository from ports.reading_query_repository import ReadingQueryRepository
_GRANULARITY_DELTA = {
"hour": relativedelta(hours=1),
"day": relativedelta(days=1),
"week": relativedelta(weeks=1),
"month": relativedelta(months=1),
}
class PgReadingQueryRepository(ReadingQueryRepository): class PgReadingQueryRepository(ReadingQueryRepository):
def __init__(self, conn: connection) -> None: def __init__(self, conn: connection) -> None:
self._conn = conn self._conn = conn
@ -20,24 +29,33 @@ class PgReadingQueryRepository(ReadingQueryRepository):
end: datetime, end: datetime,
granularity: Granularity, granularity: Granularity,
) -> list[ConsumptionPoint]: ) -> list[ConsumptionPoint]:
if start == end:
end = start + _GRANULARITY_DELTA[granularity]
adjusted_start = start - _GRANULARITY_DELTA[granularity]
date_trunc = granularity date_trunc = granularity
query = """ query = """
WITH periods AS (
SELECT SELECT
DATE_TRUNC(%s, r.date) AS period, DATE_TRUNC(%s, r.date) AS period,
MIN(r.pulses) AS pulse_start, MAX(r.pulses) AS pulse_end
MAX(r.pulses) AS pulse_end,
MAX(r.pulses) - MIN(r.pulses) AS delta_pulses
FROM reading r FROM reading r
JOIN device d ON d.device_id = r.device_id JOIN device d ON d.device_id = r.device_id
WHERE d.device_eui = %s WHERE d.device_eui = %s
AND r.date >= %s AND r.date >= %s
AND r.date < %s AND r.date < %s
GROUP BY period GROUP BY period
)
SELECT
period,
LAG(pulse_end) OVER (ORDER BY period) AS pulse_start,
pulse_end,
pulse_end - LAG(pulse_end) OVER (ORDER BY period) AS delta_pulses
FROM periods
ORDER BY period ASC ORDER BY period ASC
""" """
try: try:
with self._conn.cursor() as cur: with self._conn.cursor() as cur:
cur.execute(query, (date_trunc, dev_eui, start, end)) cur.execute(query, (date_trunc, dev_eui, adjusted_start, end))
rows = cur.fetchall() rows = cur.fetchall()
except psycopg2.DatabaseError as e: except psycopg2.DatabaseError as e:
raise DatabaseError(f"Erreur requête consumption : {e}") from e raise DatabaseError(f"Erreur requête consumption : {e}") from e
@ -51,4 +69,5 @@ class PgReadingQueryRepository(ReadingQueryRepository):
delta_m3=round(row[3] * 0.010, 3), delta_m3=round(row[3] * 0.010, 3),
) )
for row in rows for row in rows
if row[1] is not None
] ]

View file

@ -3,3 +3,4 @@ psycopg2-binary==2.9.12
pydantic==2.13.4 pydantic==2.13.4
fastapi==0.136.1 fastapi==0.136.1
uvicorn==0.46.0 uvicorn==0.46.0
python-dateutil==2.9.0

View file

@ -17,8 +17,8 @@ class ConsumptionService:
end: datetime, end: datetime,
granularity: Granularity, granularity: Granularity,
) -> ConsumptionResponse: ) -> ConsumptionResponse:
if start >= end: if start > end:
raise ValidationError("'start' doit être antérieur à 'end'") raise ValidationError("'start' doit être inférieur ou égal à 'end'")
points = self._repo.get_consumption(dev_eui, start, end, granularity) points = self._repo.get_consumption(dev_eui, start, end, granularity)