All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.azavea.stac4s.api.client.util.ClientCodecs.scala Maven / Gradle / Ivy

package com.azavea.stac4s.api.client.util

import com.azavea.stac4s.TemporalExtent

import cats.syntax.apply._
import cats.syntax.either._
import io.circe.{Decoder, Encoder}

import java.time.Instant

trait ClientCodecs {

  // TemporalExtent STAC API compatible serialization
  // Ported from https://github.com/azavea/franklin/
  private def stringToInstant(s: String): Either[Throwable, Instant] =
    Either.catchNonFatal(Instant.parse(s))

  private def temporalExtentToString(te: TemporalExtent): String =
    te match {
      case TemporalExtent(Some(start), Some(end)) if start != end => s"${start.toString}/${end.toString}"
      case TemporalExtent(Some(start), Some(end)) if start == end => s"${start.toString}"
      case TemporalExtent(Some(start), _)                         => s"${start.toString}/.."
      case TemporalExtent(_, Some(end))                           => s"../${end.toString}"
      case _                                                      => "../.."
    }

  private def temporalExtentFromString(str: String): Either[String, TemporalExtent] = {
    str.split("/").toList match {
      case ".." :: endString :: _ =>
        val parsedEnd = stringToInstant(endString)
        parsedEnd match {
          case Left(_)             => s"Could not decode instant: $str".asLeft
          case Right(end: Instant) => TemporalExtent(None, end).asRight
        }
      case startString :: ".." :: _ =>
        val parsedStart = stringToInstant(startString)
        parsedStart match {
          case Left(_)               => s"Could not decode instant: $str".asLeft
          case Right(start: Instant) => TemporalExtent(start, None).asRight
        }
      case startString :: endString :: _ =>
        val parsedStart = stringToInstant(startString)
        val parsedEnd   = stringToInstant(endString)
        (parsedStart, parsedEnd).tupled match {
          case Left(_)                               => s"Could not decode instant: $str".asLeft
          case Right((start: Instant, end: Instant)) => TemporalExtent(start, end).asRight
        }
      case _ =>
        Either.catchNonFatal(Instant.parse(str)) match {
          case Left(_)           => s"Could not decode instant: $str".asLeft
          case Right(t: Instant) => TemporalExtent(t, t).asRight
        }
    }
  }

  implicit lazy val encoderTemporalExtent: Encoder[TemporalExtent] =
    Encoder.encodeString.contramap[TemporalExtent](temporalExtentToString)

  implicit lazy val decoderTemporalExtent: Decoder[TemporalExtent] =
    Decoder.decodeString.emap(temporalExtentFromString)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy