Skip to content

Instantly share code, notes, and snippets.

@tjarvstrand
Last active February 14, 2021 10:41
Show Gist options
  • Save tjarvstrand/529ac4f9f93d87621aa99988469642b3 to your computer and use it in GitHub Desktop.
Save tjarvstrand/529ac4f9f93d87621aa99988469642b3 to your computer and use it in GitHub Desktop.
package com.example
import akka.http.scaladsl.model.Uri
import enumeratum.{Circe => Enumeratum}
import enumeratum.Enum
import enumeratum.EnumEntry
import io.circe._
import io.circe.generic.extras.auto._
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto.deriveConfiguredCodec
import io.circe.generic.semiauto.deriveCodec
import io.circe.syntax.EncoderOps
import java.time.ZonedDateTime
object Json {
def enumeratumCodec[T <: EnumEntry](e: Enum[T]): Codec[T] = Codec.from(Enumeratum.decoder(e), Enumeratum.encoder(e))
implicit val UriCodec: Codec[Uri] = Codec.from(_.as[String].map(Uri(_)), _.toString.asJson)
implicit val ZonedDateTimeCodec: Codec[ZonedDateTime] =
Codec.from(_.as[String].map(ZonedDateTime.parse(_)), _.toString.asJson)
implicit val config: Configuration = Configuration.default
.withDiscriminator("type")
.withSnakeCaseConstructorNames
implicit val ActivityCodec: Codec[Activity] = deriveConfiguredCodec
implicit val ContentCodec: Codec[Activity.Content] = deriveCodec
implicit val ParentCodec: Codec[Activity.Parent] = deriveCodec
implicit val TargetCodec: Codec[Activity.Target] = deriveCodec
implicit val TargetTypeCodec: Codec[Activity.Target.Type] = enumeratumCodec(Activity.Target.Type)
implicit val UserCodec: Codec[User] = deriveConfiguredCodec
implicit val AttachmentCodec: Codec[Activity.Content.Attachment] = Codec.from(
cursor => cursor.get[Uri]("image")
.map(Activity.Content.Attachment.Image)
.orElse(cursor.get[Uri]("video").map(Activity.Content.Attachment.Video)),
{
case image: Activity.Content.Attachment.Image => Map("image" -> image.image).asJson
case video: Activity.Content.Attachment.Video => Map("video" -> video.video).asJson
}
)
val ImplementedEvents = Set("activity_created", "activity_updated")
implicit val EventCodec: Codec[Event] = {
implicit val config: Configuration = Json.config
.withDiscriminator("event")
.copy(transformConstructorNames = Configuration.snakeCaseTransformation(_) match {
case n if ImplementedEvents.contains(n) => n
case _ => "unimplemented_event"
})
deriveConfiguredCodec[Event]
}
}
sealed trait Event {
def unique_id: String
def timestamp: ZonedDateTime
def version: Int
}
object Event {
case class ActivityCreated(unique_id: String,
activity: Activity,
timestamp: ZonedDateTime,
version: Int = 2
) extends Event
case class ActivityUpdated(unique_id: String,
activity: Activity,
timestamp: ZonedDateTime,
version: Int = 2) extends Event
case class UnimplementedEvent(unique_id: String,
timestamp: ZonedDateTime,
version: Int = 2) extends Event
}
object Activity {
case class Parent(id: String, author: User)
object Target {
sealed abstract class Type extends EnumEntry.Lowercase
object Type extends Enum[Type] {
case object Topic extends Type
case object Group extends Type
case object User extends Type
override def values: IndexedSeq[Type] = findValues
}
}
case class Target(id: String, `type`: Target.Type)
object Content {
sealed abstract class Attachment
object Attachment {
case class Video(video: Uri) extends Attachment
case class Image(image: Uri) extends Attachment
}
}
case class Content(language: String,
text: String,
enriched_text: String,
attachments: Seq[Content.Attachment])
}
sealed trait Activity {
def id: String
def author: User
def content: Activity.Content
def target: Activity.Target
def created_at: ZonedDateTime
def version: String
}
case class Post(id: String,
author: User,
content: Activity.Content,
target: Activity.Target,
created_at: ZonedDateTime,
version: String = "2") extends Activity
case class Comment(id: String,
author: User,
content: Activity.Content,
target: Activity.Target,
parent: Activity.Parent,
created_at: ZonedDateTime,
version: String = "2") extends Activity
case class User(id: String,
display_name: String,
avatar: String,
identities: Map[String, String],
public_properties: Map[String, String],
private_properties: Map[String, String])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment