-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extension typeclasses #85
Changes from all commits
d4eea57
a542890
dbfed6d
a28eccd
6228757
d007214
949f318
dba2160
c97c2cb
c842be5
02b2e5b
304f2a2
5b3aec8
3f9cfb4
d95ba5e
5c1d81f
2e89e74
9a349f5
aa8a265
75a67f9
680f399
6dcbdc1
853d9b6
ade5ae9
36721b3
8f0ad3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,73 @@ | ||
package com.azavea.stac4s | ||
|
||
import cats.Eq | ||
import cats.implicits._ | ||
import io.circe._ | ||
import io.circe.refined._ | ||
import io.circe.syntax._ | ||
import shapeless.LabelledGeneric | ||
import shapeless.ops.record.Keys | ||
|
||
final case class ItemCollection( | ||
_type: String = "FeatureCollection", | ||
stacVersion: StacVersion, | ||
stacExtensions: List[String], | ||
features: List[StacItem], | ||
links: List[StacLink] | ||
links: List[StacLink], | ||
extensionFields: JsonObject = ().asJsonObject | ||
) | ||
|
||
object ItemCollection { | ||
|
||
private val generic = LabelledGeneric[ItemCollection] | ||
private val keys = Keys[generic.Repr].apply | ||
val itemCollectionFields = keys.toList.flatMap(field => substituteFieldName(field.name)).toSet | ||
|
||
implicit val eqItemCollection: Eq[ItemCollection] = Eq.fromUniversalEquals | ||
|
||
implicit val encItemCollection: Encoder[ItemCollection] = Encoder.forProduct5( | ||
"type", | ||
"stac_version", | ||
"stac_extensions", | ||
"features", | ||
"links" | ||
)(itemCollection => | ||
implicit val encItemCollection: Encoder[ItemCollection] = new Encoder[ItemCollection] { | ||
|
||
def apply(collection: ItemCollection): Json = { | ||
val baseEncoder: Encoder[ItemCollection] = Encoder.forProduct5( | ||
"type", | ||
"stac_version", | ||
"stac_extensions", | ||
"features", | ||
"links" | ||
)(itemCollection => | ||
( | ||
itemCollection._type, | ||
itemCollection.stacVersion, | ||
itemCollection.stacExtensions, | ||
itemCollection.features, | ||
itemCollection.links | ||
) | ||
) | ||
|
||
baseEncoder(collection).deepMerge(collection.extensionFields.asJson) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the first big increase in verbosity-- everything with |
||
} | ||
} | ||
|
||
implicit val decItemCollection: Decoder[ItemCollection] = { c: HCursor => | ||
( | ||
itemCollection._type, | ||
itemCollection.stacVersion, | ||
itemCollection.stacExtensions, | ||
itemCollection.features, | ||
itemCollection.links | ||
c.get[String]("type"), | ||
c.get[StacVersion]("stac_version"), | ||
c.get[Option[List[String]]]("stac_extensions"), | ||
c.get[List[StacItem]]("features"), | ||
c.get[Option[List[StacLink]]]("links"), | ||
c.value.as[JsonObject] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's the second part of the big increase in verbosity -- derivation is no longer correct for any of these, since we need "root document without the vanilla fields" |
||
).mapN( | ||
( | ||
_type: String, | ||
stacVersion: StacVersion, | ||
extensions: Option[List[String]], | ||
features: List[StacItem], | ||
links: Option[List[StacLink]], | ||
document: JsonObject | ||
) => | ||
ItemCollection(_type, stacVersion, extensions getOrElse Nil, features, links getOrElse Nil, document.filter({ | ||
case (k, _) => !itemCollectionFields.contains(k) | ||
jisantuc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
})) | ||
) | ||
) | ||
|
||
implicit val decItemCollection: Decoder[ItemCollection] = Decoder.forProduct5( | ||
"type", | ||
"stac_version", | ||
"stac_extensions", | ||
"features", | ||
"links" | ||
)(ItemCollection.apply) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,79 @@ | ||
package com.azavea.stac4s | ||
|
||
import cats.Eq | ||
import cats.implicits._ | ||
import io.circe._ | ||
import io.circe.syntax._ | ||
import shapeless.LabelledGeneric | ||
import shapeless.ops.record.Keys | ||
|
||
final case class StacCatalog( | ||
stacVersion: String, | ||
stacExtensions: List[String], | ||
id: String, | ||
title: Option[String], | ||
description: String, | ||
links: List[StacLink] | ||
links: List[StacLink], | ||
extensionFields: JsonObject = ().asJsonObject | ||
) | ||
|
||
object StacCatalog { | ||
|
||
private val generic = LabelledGeneric[StacCatalog] | ||
private val keys = Keys[generic.Repr].apply | ||
val catalogFields = keys.toList.flatMap(field => substituteFieldName(field.name)).toSet | ||
|
||
implicit val eqStacCatalog: Eq[StacCatalog] = Eq.fromUniversalEquals | ||
|
||
implicit val encCatalog: Encoder[StacCatalog] = | ||
Encoder.forProduct6("stac_version", "stac_extensions", "id", "title", "description", "links")(catalog => | ||
implicit val encCatalog: Encoder[StacCatalog] = new Encoder[StacCatalog] { | ||
|
||
def apply(catalog: StacCatalog): Json = { | ||
val baseEncoder: Encoder[StacCatalog] = | ||
Encoder.forProduct6("stac_version", "stac_extensions", "id", "title", "description", "links")(catalog => | ||
( | ||
catalog.stacVersion, | ||
catalog.stacExtensions, | ||
catalog.id, | ||
catalog.title, | ||
catalog.description, | ||
catalog.links | ||
) | ||
) | ||
|
||
baseEncoder(catalog).deepMerge(catalog.extensionFields.asJson) | ||
pomadchin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
implicit val decCatalog: Decoder[StacCatalog] = { c: HCursor => | ||
( | ||
c.get[String]("stac_version"), | ||
c.get[List[String]]("stac_extensions"), | ||
c.get[String]("id"), | ||
c.get[Option[String]]("title"), | ||
c.get[String]("description"), | ||
c.get[List[StacLink]]("links"), | ||
c.value.as[JsonObject] | ||
).mapN( | ||
( | ||
catalog.stacVersion, | ||
catalog.stacExtensions, | ||
catalog.id, | ||
catalog.title, | ||
catalog.description, | ||
catalog.links | ||
) | ||
version: String, | ||
extensions: List[String], | ||
id: String, | ||
title: Option[String], | ||
description: String, | ||
links: List[StacLink], | ||
document: JsonObject | ||
) => | ||
StacCatalog.apply( | ||
version, | ||
extensions, | ||
id, | ||
title, | ||
description, | ||
links, | ||
document.filter({ | ||
case (k, _) => !catalogFields.contains(k) | ||
}) | ||
) | ||
) | ||
|
||
implicit val decCatalog: Decoder[StacCatalog] = | ||
Decoder.forProduct6("stac_version", "stac_extensions", "id", "title", "description", "links")(StacCatalog.apply) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we put it into a single function to reduce some boilerplate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the thing I had trouble with implicits with -- it wasn't obvious to me how to get the implicit evidence required to have
getFieldNames[T]
cooperate. Specifically, the evidence provided in the example blog post:was insufficient for
Keys[generic.Repr]
when I tried making it generic.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened #89