Skip to content

Instantly share code, notes, and snippets.

@yusefnapora
Created March 22, 2016 22:07
Show Gist options
  • Save yusefnapora/a23ec9b990fe8ef0b1a7 to your computer and use it in GitHub Desktop.
Save yusefnapora/a23ec9b990fe8ef0b1a7 to your computer and use it in GitHub Desktop.
Hashable marshalling
// The idea here is that case classes that extend `Hashable` will be converted to
// a Json AST using json4s, then written as canonical CBOR & hashed with SHA-256
//
// The actual hashing happens in `MultiHash.forHashable`, which can fail if the
// Json conversion fails.
//
// I don't think this custom marshaller trick will work for signatures, though,
// because it needs the signing key as an input, which wouldn't be available to
// the gremlin-scala marshaller.
//
// but the marshaller is too "magical" anyway, and I think it's best avoided.
//
trait Hashable {
val excludedFields: List[String] = List("id")
def multiHash: Xor[ConversionToJsonFailed, MultiHash] =
MultiHash.forHashable(this)
}
object Hashable {
// Extend the default `Marshallable` implementation for `Hashable` case classes
// to include the computed `multiHash` as a vertex property.
//
// The default marshaller will only store the constructor parameters for a case class.
// Since the hash is a computed property, it doesn't get stored by default.
// This method creates a new `Marshallable` that will include the `multiHash`
def marshaller[CC <: Hashable with Product : Marshallable]: Marshallable[CC] = {
new Marshallable[CC] {
override def fromCC(cc: CC): FromCC = {
val defaultFromCC = implicitly[Marshallable[CC]].fromCC(cc)
val valueMap = cc.multiHash match {
case Xor.Right(multiHash) =>
defaultFromCC.valueMap +
("multiHash" -> multiHash.base58)
case _ =>
defaultFromCC.valueMap
}
FromCC(defaultFromCC.id, defaultFromCC.label, valueMap)
}
override def toCC(id: Id, valueMap: ValueMap): CC =
implicitly[Marshallable[CC]]
.toCC(id, valueMap + ("id" -> id))
}
}
}
implicit val canonicalMarshaller = Hashable.marshaller[Canonical]
implicit val rawMetadataBlobMarshaller = Hashable.marshaller[RawMetadataBlob]
implicit val photoBlobMarshaller = Hashable.marshaller[PhotoBlob]
implicit val personMarshaller = Hashable.marshaller[Person]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment