Files
WeatherTool/src/main/scala/parse/Aggregate.scala
T
2023-05-03 00:02:59 +03:00

125 lines
4.7 KiB
Scala

package parse
import cats.implicits.{catsSyntaxOptionId, toFoldableOps}
import io.circe.generic.semiauto.deriveEncoder
import io.circe.syntax.EncoderOps
import io.circe.{Encoder, Json}
import parse.Parser.parseLine
object Aggregate {
case class UserQuery(
cities: List[String],
field: String,
key: AggregateKey
)
sealed trait AggregateKey
object AggregateKey {
case object Min extends AggregateKey
case object Max extends AggregateKey
case object Avg extends AggregateKey
case object Sum extends AggregateKey
case object List extends AggregateKey
case object Distinct extends AggregateKey
def fromString(str: String): Option[AggregateKey] = str match {
case "min" => Some(AggregateKey.Min)
case "max" => Some(AggregateKey.Max)
case "avg" => Some(AggregateKey.Avg)
case "sum" => Some(AggregateKey.Sum)
case "list" => Some(AggregateKey.List)
case "distinct" => Some(AggregateKey.Distinct)
case _ => None
}
def getKeys: List[String] = {
val runtimeMirror = scala.reflect.runtime.currentMirror
val classSymbol = runtimeMirror.classSymbol(classOf[AggregateKey])
// Get all case classes that extend the AggregateKey trait
val keys = classSymbol.knownDirectSubclasses.map(_.name.toString).toList
keys
}
}
sealed trait AggregateValue
case class DoubleValue(value: Double) extends AggregateValue
case class ListOptionValue(list: List[Option[Double]]) extends AggregateValue
case class StringListList(list: List[List[String]]) extends AggregateValue
case class DistinctStringList(list: List[String]) extends AggregateValue
object AggregateValue {
def getKeys: List[String] = {
val runtimeMirror = scala.reflect.runtime.currentMirror
val classSymbol = runtimeMirror.classSymbol(classOf[AggregateValue])
// Get all case classes that extend the AggregateValue trait
val keys = classSymbol.knownDirectSubclasses.map(_.name.toString).toList
keys
}
}
object AggregateValueImplicits {
implicit val aggregateValueEncoder: Encoder[AggregateValue] = Encoder.instance {
case doubleValue: DoubleValue => doubleValue.asJson
case listOptionValue: ListOptionValue => listOptionValue.asJson
case stringListList: StringListList => stringListList.asJson
case distinctStringList: DistinctStringList => distinctStringList.asJson
}
implicit val doubleValueEncoder: Encoder[DoubleValue] = Encoder.instance {
case DoubleValue(value) if !value.isNaN => Json.fromDouble(value).get
case _ => Json.Null
}
implicit val listOptionValueEncoder: Encoder[ListOptionValue] = deriveEncoder[ListOptionValue]
implicit val stringListListEncoder: Encoder[StringListList] = deriveEncoder[StringListList]
implicit val distinctStringListEncoder: Encoder[DistinctStringList] = deriveEncoder[DistinctStringList]
}
def extractDoubleFieldValues(field: String, weatherData: List[WeatherData]): List[Option[Double]] =
field match {
case "tempMax" => weatherData.map(_.tempMax)
case "tempMin" => weatherData.map(_.tempMin)
case "tempAvg" => weatherData.map(_.tempAvg)
case "precipitation" => weatherData.map(_.precipitation)
case "windAvg" => weatherData.map(_.windAvg)
case "windMax" => weatherData.map(_.windMax)
case "visibilityMin" => weatherData.map(_.visibilityMin)
case "visibilityAvg" => weatherData.map(_.visibilityAvg)
case "snowAvg" => weatherData.map(_.snowAvg)
case "atmPressire" => weatherData.map(_.atmPressure)
case "dewPoint" => weatherData.map(_.dewPoint)
case "humidity" => weatherData.map(_.humidity)
case "sunDuration" => weatherData.map(_.sunDuration)
// case "phenomena" => weatherData.map(_..phenomena)
case _ => List.empty
}
def aggregateDoubleValues(
AggKey: AggregateKey,
values: List[Option[Double]]
): Option[AggregateValue] = {
val flatValues = values.flatten
AggKey match {
case AggregateKey.Min => flatValues.minimumOption.map(DoubleValue)
case AggregateKey.Max => flatValues.maximumOption.map(DoubleValue)
case AggregateKey.Avg => flatValues.reduceOption(_ + _).map(sum => DoubleValue(sum / flatValues.length))
case AggregateKey.Sum => flatValues.sum.some.map(DoubleValue)
case AggregateKey.List => ListOptionValue(values).some
case AggregateKey.Distinct => None
}
}
def aggregatePhenomenaValues(
aggregationType: AggregateKey,
values: List[List[String]]
): Option[AggregateValue] =
aggregationType match {
case AggregateKey.List => StringListList(values).some
case AggregateKey.Distinct => DistinctStringList(values.flatten.distinct).some
case _ => None
}
}