Query and display phenomena

This commit is contained in:
Guntis Smaukstelis
2024-02-08 22:48:27 +02:00
parent a70fe56a82
commit 23c0990495
4 changed files with 48 additions and 17 deletions
+6 -6
View File
@@ -45,22 +45,22 @@ object Main {
// } yield re // } yield re
val formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmm") val formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmm")
val from = LocalDateTime.parse("20240110_1000", formatter) val from = LocalDateTime.parse("20240207_1000", formatter)
val to = LocalDateTime.parse("20240111_1000", formatter) val to = LocalDateTime.parse("20240208_1400", formatter)
// val cities = NonEmptyList.of("Ainaži", "Rīga", "Kolka", "Vičaki") val cities = NonEmptyList.of("Ainaži", "Rīga", "Kolka", "Vičaki")
// val cities = NonEmptyList.of("Rīga") // val cities = NonEmptyList.of("Rīga")
// val query = UserQuery(cities, "tempMax", AggregateKey.List, ChronoUnit.DAYS, from, to) val query = UserQuery(cities, "phenomena", AggregateKey.List, ChronoUnit.DAYS, from, to)
val re = for { val re = for {
postgresService <- PostgresService.of(xa) postgresService <- PostgresService.of(xa)
re <- postgresService.queryCityAllFields("Rīga", from, to) re <- postgresService.query(query)
} yield re } yield re
// val jssson = re.map(result => ResponseWrapper(result, query)) // val jssson = re.map(result => ResponseWrapper(result, query))
// .map(responseWrapper => responseWrapper.asJson.pretty) // .map(responseWrapper => responseWrapper.asJson.pretty)
println(re.unsafeRunSync()) println(re.unsafeRunSync().asJson.pretty)
// println(jssson.unsafeRunSync()) // println(jssson.unsafeRunSync())
+30 -4
View File
@@ -11,8 +11,12 @@ import java.time.{LocalDate, LocalDateTime, OffsetDateTime}
import doobie.postgres.implicits._ import doobie.postgres.implicits._
import org.typelevel.log4cats.Logger import org.typelevel.log4cats.Logger
import org.typelevel.log4cats.slf4j.Slf4jLogger import org.typelevel.log4cats.slf4j.Slf4jLogger
import parse.Aggregate.{AggregateKey, AggregateValue, DoubleValue, TimeDoubleList, UserQuery} import parse.Aggregate.{AggregateKey, AggregateValue, DistinctStringList, DoubleValue, TimeDoubleList, UserQuery}
import parse.{Parser, WeatherStationData} import parse.{Parser, WeatherStationData}
import shapeless.syntax.std.tuple.productTupleOps
import io.circe._
import io.circe.parser._
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
import scala.util.matching.Regex import scala.util.matching.Regex
@@ -101,9 +105,31 @@ class PostgresService(transactor: Transactor[IO], log: Logger[IO]) {
} }
def query(userQuery: UserQuery): IO[Map[String, Option[AggregateValue]]] = { def query(userQuery: UserQuery): IO[Map[String, Option[AggregateValue]]] = {
if (userQuery.field == "phenomena") { // this handles strings if (userQuery.field == "phenomena") {
// TODO query list and distinct values from phenomena val query =
IO(Map()) // empty result fr"""
SELECT city, array_to_json(array_agg(phenomena)) AS aggregated_phenomena
FROM weather
WHERE """ ++ Fragments.in(fr"city", userQuery.cities) ++
fr" AND dateTime BETWEEN ${userQuery.from} AND ${userQuery.to}" ++
fr" GROUP BY city, phenomena"
query.query[(String, Option[String])]
.to[List]
.transact(transactor)
.map { resultList =>
resultList
.flatMap {
case (city, jsonOption) =>
jsonOption.flatMap { jsonString =>
parse(jsonString).toOption.flatMap(_.as[List[List[String]]].toOption.map(_.flatten.distinct))
}.map(phenomena => (city, phenomena.filter(_.nonEmpty)))
}
.groupBy(_._1)
.view.mapValues(_.flatMap(_._2).distinct).toMap
.map { case (city, phenomenaList) => city -> Option(DistinctStringList(phenomenaList)) }
}
} else if (List( } else if (List(
AggregateKey.Max, AggregateKey.Max,
AggregateKey.Min, AggregateKey.Min,
+3 -1
View File
@@ -93,7 +93,9 @@ object Aggregate {
implicit val stringListListEncoder: Encoder[StringListList] = Encoder.instance { sllValue => implicit val stringListListEncoder: Encoder[StringListList] = Encoder.instance { sllValue =>
Json.arr(sllValue.list.map(_.asJson): _*) Json.arr(sllValue.list.map(_.asJson): _*)
} }
implicit val distinctStringListEncoder: Encoder[DistinctStringList] = deriveEncoder[DistinctStringList] implicit val distinctStringListEncoder: Encoder[DistinctStringList] = Encoder.instance { dslistValue =>
Json.arr(dslistValue.list.map(_.asJson): _*)
}
} }
private def convertDateTime(granularity: ChronoUnit)(data: (LocalDateTime, _)): String = { private def convertDateTime(granularity: ChronoUnit)(data: (LocalDateTime, _)): String = {
+9 -6
View File
@@ -1,4 +1,4 @@
import { Component } from "solid-js"; import { Component, Match, Switch } from "solid-js";
import { CityChart } from "../../components/chart/CityChart"; import { CityChart } from "../../components/chart/CityChart";
import { DataQuery } from "../helpers"; import { DataQuery } from "../helpers";
@@ -7,11 +7,14 @@ export const GridResult: Component<{ city: string, query: DataQuery, result: any
return ( return (
<div class="item"> <div class="item">
<h4>{ city }</h4> <h4>{ city }</h4>
{ <Switch fallback={<p>{ result }</p>}>
isDateNumber(result) <Match when={query.field === "phenomena"}>
? <CityChart city={()=>city} data={()=>result} query={()=>query}/> { result.join(", ") }
: <p>{ result }</p> </Match>
} <Match when={isDateNumber(result)}>
<CityChart city={()=>city} data={()=>result} query={()=>query}/>
</Match>
</Switch>
</div> </div>
); );
} }