From a6b2b8462c9adf1647ebddf92edb0e41d345d6e7 Mon Sep 17 00:00:00 2001 From: b0txec Date: Tue, 25 Aug 2026 17:13:20 +0300 Subject: [PATCH] =?UTF-8?q?Fix=20Faktisk=C4=81=20showing=20blank=20tempera?= =?UTF-8?q?tures=20right=20after=20each=20new=20hour=20starts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit queryLatestTemperatures picked the single most-recent row per city with no regard for whether that row's tempAvg was actually populated yet. The open-data source publishes fields on different schedules within the same hour (snow lands well before the hourly temperature aggregate), so the freshest row for a city routinely has a real dateTime but a still-null tempAvg while the previous hour's row has good data. Confirmed live on both Rocky and the VPS: every city's newest row had tempAvg null (but a real snowAvg=0), one hour after the actual last real reading. Fixed by requiring tempAvg IS NOT NULL in the WHERE clause, so DISTINCT ON's "most recent" pick skips a fresh partial row and finds the newest row that actually has a value. Checked before changing: this is the only caller of queryLatestTemperatures (Faktiskā's fixed-station lookup); a city with zero real temperature history ever now returns no row instead of a null-valued one, which the frontend already treats identically to a present-but-null observation (falls through to the same "Nav datu" missing state either way) -- confirmed via MapGraphics.tsx before shipping, not assumed. --- src/main/scala/db/PostgresService.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/scala/db/PostgresService.scala b/src/main/scala/db/PostgresService.scala index 418323c..4ea66f9 100644 --- a/src/main/scala/db/PostgresService.scala +++ b/src/main/scala/db/PostgresService.scala @@ -29,10 +29,17 @@ object PostgresService { class PostgresService(transactor: Transactor[IO], log: Logger[IO]) { def queryLatestTemperatures(cities: NonEmptyList[String]): IO[List[(String, LocalDateTime, Option[Double])]] = { + // The open-data source publishes fields on different schedules within + // the same hour (e.g. snow arrives well before the hourly temperature + // aggregate), so the single newest row for a city can have a real + // dateTime but a still-null tempAvg. Skip straight to DISTINCT ON's + // "most recent" pick by requiring tempAvg itself to be present, so a + // fresh partial row never hides an older row that actually has data. val query = fr"SELECT DISTINCT ON (city) city, dateTime, tempAvg" ++ fr" FROM weather" ++ fr" WHERE " ++ Fragments.in(fr"city", cities) ++ + fr" AND tempAvg IS NOT NULL" ++ fr" ORDER BY city, dateTime DESC" query.query[(String, LocalDateTime, Option[Double])]