Skip to content

Instantly share code, notes, and snippets.

object SchemaReads {
def trivial[T](description: String)(implicit reads: Reads[T]) =
SchemaReads(reads, JsonSchema.Single(description))
implicit def seq[T](implicit sr: SchemaReads[T]): SchemaReads[Seq[T]] = SchemaReads(Reads.seq(sr.reads), JsonSchema.Array(sr.schema))
implicit def set[T](implicit sr: SchemaReads[T]): SchemaReads[Set[T]] = SchemaReads(Reads.set(sr.reads), JsonSchema.Array(sr.schema))
implicit val int: SchemaReads[Int] = trivial("int")
implicit val str: SchemaReads[String] = trivial("str")
implicit class PimpedJsPath(jsp: JsPath) {
def readWithSchema[T](implicit sr: SchemaReads[T]) =
sealed abstract class JsonSchema {
def asJson: JsValue
}
object JsonSchema {
final case class Single(description: String) extends JsonSchema { def asJson = JsString(description) }
final case class Optional(field: JsonSchema) extends JsonSchema { def asJson = field.asJson }
final case class Array(kind: JsonSchema) extends JsonSchema { def asJson = Json.arr(kind.asJson) }
final case class Object(fields: Seq[(String, JsonSchema)]) extends JsonSchema {
def asJson = JsObject(fields.map {
case (name, JsonSchema.Optional(schema)) => (name + "?") -> schema.asJson
case class SchemaReads[T](reads: Reads[T], schema: JsonSchema) {
def map[S](f: T => S) = SchemaReads(reads map f, schema)
}
val reads: Reads[Input] = (
(__ \ "url").read[URL] and
(__ \ "title").read[String] and
(__ \ "source").read[URLSource] and
(__ \ "groupId").readNullable[Id[Group]] and
(__ \ "taggedUsers").readNullable[Seq[Id[User]]].fmap(_ getOrElse Seq.empty)
)(Input.apply _)
case class Input(
url: URL,
title: String,
source: URLSource,
groupId: Option[Id[Group]],
taggedUsers: Seq[Id[User]])
import SlackErrorCode._
def tryToUpdateMessage(token: SlackAccessToken, channel: SlackChannelId, ts: SlackTimestamp, newText: String): Future[Unit] = {
val updateRequest = SlackMessageUpdateRequest(
text = newText,
attachments = Seq.empty,
unfurlLinks = false,
unfurlMedia = false,
parseMode = "none"
)
slackClient.updateMessage(token, channel, ts, updateRequest)
case class Public(value: String) extends SlackChannelId("C")
case class Private(value: String) extends SlackChannelId("G")
case class DM(value: String) extends SlackChannelId("D")
case class User(value: String) extends SlackChannelId("U")
private def parseChannelId(value: String): Try[SlackChannelId] = value.headOption match {
case Some('C') => Success(Public(value))
case Some('G') => Success(Private(value))
case Some('D') => Success(DM(value))
case Some('U') => Success(User(value))
@json case class SlackTimestamp(value: String) extends Ordered[SlackTimestamp] { // channel-specific timestamp
def compare(that: SlackTimestamp) = value compare that.value
def toDateTime: DateTime = Try {
// "The bit before the . is a unix timestamp, the bit after is a sequence to guarantee uniqueness."
new DateTime(value.split('.').head.toLong * 1000)
}.getOrElse(throw new Exception(s"Could not parse a date-time out of $value"))
}
def runBF[T](bf: BatchFetchable[T]): T = {
val entities = Entities(
users = getManyUsersFromDb(bf.keys.users),
groups = getManyGroupsFromDb(bf.keys,groups),
posts = getManyPostsFromDb(bf.keys.posts),
msgs = getManyMsgsFromDb(bf.keys.msgs)
)
bf.run(entities)
}
(BatchFetchable.user(userId) and BatchFetchable.group(groupId)).tupled.map {
case (user, group) => s"${user.fullName} is part of ${group.name}"
}