From 1fd2c80778fe3bae1aa86fe074bddea93dc8f0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20L=C3=BChrs?= Date: Tue, 19 Oct 2021 15:31:12 -0300 Subject: [PATCH] Added some general use decoders. --- .../main/scala/lucuma/schemas/decoders.scala | 138 ++++++++++++++++++ .../scala/lucuma/schemas/ObservationDB.scala | 15 +- 2 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 lucuma-schemas/src/main/scala/lucuma/schemas/decoders.scala diff --git a/lucuma-schemas/src/main/scala/lucuma/schemas/decoders.scala b/lucuma-schemas/src/main/scala/lucuma/schemas/decoders.scala new file mode 100644 index 00000000..5a3ac278 --- /dev/null +++ b/lucuma-schemas/src/main/scala/lucuma/schemas/decoders.scala @@ -0,0 +1,138 @@ +// Copyright (c) 2016-2021 Association of Universities for Research in Astronomy, Inc. (AURA) +// For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause + +package lucuma.schemas + +import cats.syntax.all.none +import coulomb._ +import eu.timepit.refined.types.numeric.PosInt +import io.circe.{ Decoder, DecodingFailure, HCursor } +import io.circe.generic.semiauto +import io.circe.refined._ +import lucuma.core.`enum`.{ MagnitudeBand, MagnitudeSystem } +import lucuma.core.math.{ + Angle, + Coordinates, + Declination, + Epoch, + MagnitudeValue, + Parallax, + ProperMotion, + RadialVelocity, + RightAscension, + Wavelength +} +import lucuma.core.math.units.CentimetersPerSecond +import lucuma.core.model.{ Magnitude, SiderealTracking } + +import java.time.Duration +import java.time.temporal.ChronoUnit + +object decoders { + implicit val epochDecoder: Decoder[Epoch] = + Decoder.decodeString.emap(e => + Epoch.fromString.getOption(e).toRight(s"Invalid epoch value: $e") + ) + + val rvmsDecoder: Decoder[RadialVelocity] = + Decoder.decodeBigDecimal.emap(x => + RadialVelocity(x.withUnit[CentimetersPerSecond]).toRight(s"Invalid radial velocity $x") + ) + + implicit val rvDecoder: Decoder[RadialVelocity] = new Decoder[RadialVelocity] { + final def apply(c: HCursor): Decoder.Result[RadialVelocity] = + c.downField("centimetersPerSecond").as[RadialVelocity](rvmsDecoder) + } + + val pxµasDecoder: Decoder[Parallax] = + Decoder.decodeLong.map(Parallax.fromMicroarcseconds) + + implicit val pxDecoder: Decoder[Parallax] = new Decoder[Parallax] { + final def apply(c: HCursor): Decoder.Result[Parallax] = + c.downField("microarcseconds").as[Parallax](pxµasDecoder) + } + + val raµasDecoder: Decoder[RightAscension] = + Decoder.decodeLong + .map( + (RightAscension.fromAngleExact.getOption _).compose(Angle.fromMicroarcseconds _) + ) + .map(_.getOrElse(RightAscension.Zero)) + + implicit val raDecoder: Decoder[RightAscension] = new Decoder[RightAscension] { + final def apply(c: HCursor): Decoder.Result[RightAscension] = + c.downField("microarcseconds").as[RightAscension](raµasDecoder) + } + + val decµasDecoder: Decoder[Declination] = + Decoder.decodeLong + .map( + (Declination.fromAngle.getOption _).compose(Angle.fromMicroarcseconds _) + ) + .emap(_.toRight("Invalid µarcsec value for declination")) + + implicit val decDecoder: Decoder[Declination] = new Decoder[Declination] { + final def apply(c: HCursor): Decoder.Result[Declination] = + c.downField("microarcseconds").as[Declination](decµasDecoder) + } + + implicit val coordDecoder: Decoder[Coordinates] = semiauto.deriveDecoder[Coordinates] + + val pmraµasDecoder: Decoder[ProperMotion.RA] = + Decoder.decodeLong + .map(ProperMotion.RA.microarcsecondsPerYear.reverseGet) + + implicit val pmraDecoder: Decoder[ProperMotion.RA] = new Decoder[ProperMotion.RA] { + final def apply(c: HCursor): Decoder.Result[ProperMotion.RA] = + c.downField("microarcsecondsPerYear").as[ProperMotion.RA](pmraµasDecoder) + } + + val pmdecµasDecoder: Decoder[ProperMotion.Dec] = + Decoder.decodeLong + .map(ProperMotion.Dec.microarcsecondsPerYear.reverseGet) + + implicit val pmdecDecoder: Decoder[ProperMotion.Dec] = new Decoder[ProperMotion.Dec] { + final def apply(c: HCursor): Decoder.Result[ProperMotion.Dec] = + c.downField("microarcsecondsPerYear").as[ProperMotion.Dec](pmdecµasDecoder) + } + + implicit val pmDecoder: Decoder[ProperMotion] = semiauto.deriveDecoder[ProperMotion] + + implicit val siderealTrackingDecoder = new Decoder[SiderealTracking] { + final def apply(c: HCursor): Decoder.Result[SiderealTracking] = + for { + bc <- c.downField("coordinates").as[Coordinates] + ep <- c.downField("epoch").as[Epoch] + pm <- c.downField("properMotion").as[Option[ProperMotion]] + rv <- c.downField("radialVelocity").as[Option[RadialVelocity]] + par <- c.downField("parallax").as[Option[Parallax]] + } yield SiderealTracking(none, bc, ep, pm, rv, par) + } + + implicit val magnitudeValueDecoder: Decoder[MagnitudeValue] = new Decoder[MagnitudeValue] { + final def apply(c: HCursor): Decoder.Result[MagnitudeValue] = + c.as[BigDecimal] + .map(MagnitudeValue.fromBigDecimal.getOption) + .flatMap(_.toRight(DecodingFailure("Invalid MagnitudeValue", c.history))) + } + + implicit val magnitudeDecoder: Decoder[Magnitude] = new Decoder[Magnitude] { + final def apply(c: HCursor): Decoder.Result[Magnitude] = + for { + v <- c.downField("value").as[MagnitudeValue] + b <- c.downField("band").as[MagnitudeBand] + s <- c.downField("system").as[MagnitudeSystem] + } yield Magnitude(v, b, s) + } + + implicit val durationDecoder: Decoder[Duration] = Decoder.instance( + _.downField("microseconds") + .as[Long] + .map(l => Duration.of(l, ChronoUnit.MICROS)) + ) + + implicit val wavelengthDecoder: Decoder[Wavelength] = Decoder.instance( + _.downField("picometers").as[PosInt].map(Wavelength.apply) + ) + +} diff --git a/templates/src/main/scala/lucuma/schemas/ObservationDB.scala b/templates/src/main/scala/lucuma/schemas/ObservationDB.scala index 354cee63..f11c9324 100644 --- a/templates/src/main/scala/lucuma/schemas/ObservationDB.scala +++ b/templates/src/main/scala/lucuma/schemas/ObservationDB.scala @@ -7,6 +7,7 @@ import clue.annotation.GraphQLSchema import lucuma.core.enum import lucuma.core.model import lucuma.core.model._ +import lucuma.core.math // gql: import io.circe.refined._ @GraphQLSchema @@ -85,6 +86,18 @@ trait ObservationDB { } object Types { - type Duration = java.time.Duration + type Coordinates = math.Coordinates + type Declination = math.Declination + type Duration = java.time.Duration + type Magnitude = model.Magnitude + type Parallax = math.Parallax + type ProperMotion = math.ProperMotion + type ProperMotionDeclination = math.ProperMotion.Dec + type ProperMotionRA = math.ProperMotion.RA + type RadialVelocity = math.RadialVelocity + type RightAscension = math.RightAscension + type Sidereal = model.SiderealTracking + type Wavelength = math.Wavelength + } }