-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow items to have both time ranges and point in time datetimes (#405)
* switch item datetimes from ADT to cats Ior * remove stale old print * fix encoder order is important to avoid accidentally overwriting the datetime field * handle case where two generated datetimes are equal * Update changelog * suppress warning * update STAC versions in tests
- Loading branch information
Showing
12 changed files
with
112 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 10 additions & 22 deletions
32
modules/core/shared/src/main/scala/com/azavea/stac4s/ItemDatetime.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,30 @@ | ||
package com.azavea.stac4s | ||
|
||
import cats.kernel.Eq | ||
import cats.syntax.apply._ | ||
import cats.syntax.functor._ | ||
import io.circe.syntax._ | ||
import io.circe.{Decoder, Encoder, HCursor} | ||
|
||
import java.time.Instant | ||
|
||
sealed abstract class ItemDatetime | ||
case class PointInTime(when: Instant) | ||
|
||
object ItemDatetime { | ||
case class TimeRange(start: Instant, end: Instant) | ||
|
||
case class PointInTime(when: Instant) extends ItemDatetime | ||
|
||
case class TimeRange(start: Instant, end: Instant) extends ItemDatetime | ||
|
||
implicit val eqItemDatetime: Eq[ItemDatetime] = Eq.fromUniversalEquals | ||
|
||
implicit val decPointInTime: Decoder[PointInTime] = { cursor: HCursor => | ||
cursor.get[Instant]("datetime") map { PointInTime } | ||
} | ||
object TimeRange { | ||
|
||
implicit val decTimeRange: Decoder[TimeRange] = { cursor: HCursor => | ||
(cursor.get[Instant]("start_datetime"), cursor.get[Instant]("end_datetime")) mapN { TimeRange } | ||
(cursor.get[Instant]("start_datetime"), cursor.get[Instant]("end_datetime")) mapN { TimeRange.apply } | ||
} | ||
|
||
implicit val decItemDatetime: Decoder[ItemDatetime] = decPointInTime.widen or decTimeRange.widen | ||
|
||
implicit val encPointInTime: Encoder[PointInTime] = Encoder.forProduct1("datetime")(_.when) | ||
|
||
implicit val encTimeRange: Encoder[TimeRange] = | ||
Encoder.forProduct3("datetime", "start_datetime", "end_datetime")(range => | ||
(Option.empty[Instant], range.start, range.end) | ||
) | ||
} | ||
|
||
implicit val encItemDateTime: Encoder[ItemDatetime] = { | ||
case pit @ PointInTime(_) => pit.asJson | ||
case tr @ TimeRange(_, _) => tr.asJson | ||
object PointInTime { | ||
|
||
implicit val decPointInTime: Decoder[PointInTime] = { cursor: HCursor => | ||
cursor.get[Instant]("datetime") map { PointInTime.apply } | ||
} | ||
implicit val encPointInTime: Encoder[PointInTime] = Encoder.forProduct1("datetime")(_.when) | ||
} |
2 changes: 2 additions & 0 deletions
2
modules/core/shared/src/main/scala/com/azavea/stac4s/ItemProperties.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
modules/core/shared/src/main/scala/com/azavea/stac4s/types.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,46 @@ | ||
package com.azavea.stac4s | ||
|
||
import cats.data.Ior | ||
import cats.kernel.Eq | ||
import eu.timepit.refined.W | ||
import eu.timepit.refined.api.Refined | ||
import eu.timepit.refined.generic._ | ||
import io.circe.syntax._ | ||
import io.circe.{Decoder, DecodingFailure, Encoder, HCursor} | ||
|
||
package object types { | ||
|
||
type CatalogType = String Refined Equal[W.`"Catalog"`.T] | ||
type CollectionType = String Refined Equal[W.`"Collection"`.T] | ||
|
||
type ItemDatetime = Ior[PointInTime, TimeRange] | ||
|
||
implicit val encItemDateTime: Encoder[ItemDatetime] = { | ||
case Ior.Left(pit @ PointInTime(_)) => pit.asJson | ||
case Ior.Right(tr @ TimeRange(_, _)) => tr.asJson | ||
case Ior.Both(pit @ PointInTime(_), tr @ TimeRange(_, _)) => | ||
// order is important here! the time range encoder also writes a `null` value to the | ||
// datetime field, which overwrites what the point-in-time encoder wants to write. | ||
val out = tr.asJson.deepMerge(pit.asJson) | ||
out | ||
} | ||
|
||
implicit val decItemDateTime: Decoder[ItemDatetime] = { c: HCursor => | ||
(c.as[PointInTime], c.as[TimeRange]) match { | ||
case (Right(pit), Right(tr)) => Right(Ior.Both(pit, tr)) | ||
case (_, Right(tr)) => Right(Ior.Right(tr)) | ||
case (Right(pit), _) => Right(Ior.Left(pit)) | ||
case (Left(err1), Left(err2)) => | ||
(err1, err2) match { | ||
case (DecodingFailure(decFailure1, h1), DecodingFailure(decFailure2, h2)) => | ||
Left(DecodingFailure(s"${decFailure1}. ${decFailure2}", h1 ++ h2)) | ||
// since they're decoding the same cursor, if one of the errors is a ParsingFailure instead | ||
// of a decoding failure, they _both_ should be, so we just need the first one | ||
case _ => | ||
Left(err1) | ||
} | ||
} | ||
} | ||
|
||
implicit val eqItemDatetime: Eq[ItemDatetime] = Eq.fromUniversalEquals | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.