Skip to content

Instantly share code, notes, and snippets.

@unthingable
Last active October 20, 2015 22:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unthingable/5f7ad3aca14653c79e1e to your computer and use it in GitHub Desktop.
Save unthingable/5f7ad3aca14653c79e1e to your computer and use it in GitHub Desktop.
structural variance in json objects
object lisMessages {
case class PayloadData(name: String, newValue: JsValue, oldValue: JsValue)
case class LisPayloadA[C:Format, D:Format] (
uuid : String,
timestamp : String,
source : String,
context : C,
model : String,
data : D,
event : String,
uid : String
) {
lazy val rkey = s"$source.$model.$event"
}
def lpaFormat[C:Format, D:Format]: Format[LisPayloadA[C, D]] = (
(__ \ "uuid" ).format[String] and
(__ \ "timestamp" ).format[String] and
(__ \ "source" ).format[String] and
(__ \ "context" ).format[C] and
(__ \ "model" ).format[String] and
(__ \ "data" ).format[D] and
(__ \ "event" ).format[String] and
(__ \ "uid" ).format[String]
)(LisPayloadA.apply[C,D], unlift(LisPayloadA.unapply[C,D]))
// Different message types
type BompPayload = LisPayloadA[JsValue, List[PayloadData]]
type LisPayload = LisPayloadA[JsValue, JsValue]
implicit val bmpFormat: Format[BompPayload] = lpaFormat[JsValue, List[PayloadData]]
implicit val lisFormat: Format[LisPayload] = lpaFormat[JsValue, JsValue]
def dataMap(pl:BompPayload) = pl.data.map(x => (x.name, x)).toMap
implicit val payloadDataReads: Reads[PayloadData] = (
__(0).read[String] and
__(1).read[JsValue] and
__(2).read[JsValue]
)(PayloadData.apply _)
// not as elegant, but how else to indicate we're creating an Array?
implicit val payloadDataWrites = new Writes[PayloadData] {
def writes(p: PayloadData): JsValue = {
Json.arr(p.name, p.newValue, p.oldValue)
}
}
}
object experiment {
trait T[C<:Format[_]] {
def apply(a:String, b:String, c: C) = { new X(a,b,c) }
}
case class X[C<:Format[_]] (
val a: String,
val b: String,
val c: C
)
// Extending X requires both a trait (for the apply method) for the object
// and a class for a type. We also have to repeat the type parameter. Is there a simpler way?
object A extends T[List[String]]
type A = X[List[String]]
object B extends T[Boolean]
type B = X[Boolean]
// ... etc
val a:A = A("foo", "bar", List("xyz"))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment