io.atlassian.aws.dynamodb.Column.scala Maven / Gradle / Ivy
package io.atlassian.aws.dynamodb
import Unmarshaller._
import kadai.Attempt
import scalaz.InvariantFunctor
import scalaz.syntax.id._
sealed trait Column[A] {
self =>
def marshall: Marshaller[A]
def unmarshall: Unmarshaller[A]
// invariant map
def xmap[B](f: A => B, g: B => A): Column[B] =
new Column[B] {
override val marshall = self.marshall.contramap(g)
override val unmarshall = self.unmarshall.map(f)
}
def liftOption =
new Column[Option[A]] {
override val marshall = self.marshall.liftOption
override val unmarshall = self.unmarshall.liftOption
}
}
/**
* A specific field/column in a table. Has a name and an Encoder/Decoder to
* prepare the encoded representation to the Dynamo driver, and to return
* the de-serialized value back from the database, respectively.
*/
case class NamedColumn[A](name: String, column: Column[A])
object Column extends ColumnComposites {
def apply[A: Encoder: Decoder](s: String): NamedColumn[A] = {
val c = new Column[A] {
override val marshall = Marshaller[A] { a => Map(s -> Encoder[A].encode(a)) }
override val unmarshall = Unmarshaller.get(s)
}
NamedColumn(s, c)
}
private[dynamodb] def unmarshall[A, B](ca: Column[A], cb: Column[B])(map: DynamoMap): Attempt[(A, B)] =
for {
a <- ca.unmarshall(map)
b <- cb.unmarshall(map)
} yield (a, b)
implicit object ColumnInvariantFunctor extends InvariantFunctor[Column] {
def xmap[A, B](ca: Column[A], f: A => B, g: B => A): Column[B] =
ca.xmap(f, g)
}
}
trait ColumnComposites {
/**
* implementations define specific apply methods of the right type
* this lets us specify the composed type and infer the rest from the passed Column types
*/
trait Compose[To]
def compose2[A] = new Compose[A] {
def apply[B, C](cb: Column[B], cc: Column[C])(from: A => (B, C))(to: (B, C) => A): Column[A] =
new Column2(cb, cc)(to, from andThen Some.apply)
}
def case2[A] = new Compose[A] {
def apply[B, C](cb: Column[B], cc: Column[C])(to: (B, C) => A, from: A => Option[(B, C)]): Column[A] =
new Column2(cb, cc)(to, from)
}
def compose3[A] = new Compose[A] {
def apply[B, C, D](cb: Column[B], cc: Column[C], cd: Column[D])(from: A => (B, C, D))(to: (B, C, D) => A): Column[A] =
new Column3(cb, cc, cd)(to, from andThen Some.apply)
}
def case3[A] = new Compose[A] {
def apply[B, C, D](cb: Column[B], cc: Column[C], cd: Column[D])(to: (B, C, D) => A, from: A => Option[(B, C, D)]): Column[A] =
new Column3(cb, cc, cd)(to, from)
}
def compose4[A] = new Compose[A] {
def apply[B, C, D, E](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E])(from: A => (B, C, D, E))(to: (B, C, D, E) => A): Column[A] =
new Column4(cb, cc, cd, ce)(to, from andThen Some.apply)
}
def case4[A] = new Compose[A] {
def apply[B, C, D, E](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E])(to: (B, C, D, E) => A, from: A => Option[(B, C, D, E)]): Column[A] =
new Column4(cb, cc, cd, ce)(to, from)
}
def compose5[A] = new Compose[A] {
def apply[B, C, D, E, F](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E], cf: Column[F])(from: A => (B, C, D, E, F))(to: (B, C, D, E, F) => A): Column[A] =
new Column5(cb, cc, cd, ce, cf)(to, from andThen Some.apply)
}
def case5[A] = new Compose[A] {
def apply[B, C, D, E, F](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E], cf: Column[F])(to: (B, C, D, E, F) => A, from: A => Option[(B, C, D, E, F)]): Column[A] =
new Column5(cb, cc, cd, ce, cf)(to, from)
}
def compose6[A] = new Compose[A] {
def apply[B, C, D, E, F, G](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E], cf: Column[F], cg: Column[G])(from: A => (B, C, D, E, F, G))(to: (B, C, D, E, F, G) => A): Column[A] =
new Column6(cb, cc, cd, ce, cf, cg)(to, from andThen Some.apply)
}
def case6[A] = new Compose[A] {
def apply[B, C, D, E, F, G](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E], cf: Column[F], cg: Column[G])(to: (B, C, D, E, F, G) => A, from: A => Option[(B, C, D, E, F, G)]): Column[A] =
new Column6(cb, cc, cd, ce, cf, cg)(to, from)
}
private final class Column2[A, B, C](cb: Column[B], cc: Column[C])(to: (B, C) => A, from: A => Option[(B, C)]) extends Column[A] {
val marshall =
Marshaller[A] {
from(_).fold(Map.empty[String, Value]) { case (b, c) => append(cb.marshall(b), cc.marshall(c)) }
}
val unmarshall =
for {
b <- cb.unmarshall
c <- cc.unmarshall
} yield to(b, c)
override def toString = s"Composite($cb, $cc)"
}
private final class Column3[A, B, C, D](cb: Column[B], cc: Column[C], cd: Column[D])(to: (B, C, D) => A, from: A => Option[(B, C, D)]) extends Column[A] {
val marshall =
Marshaller[A] {
from(_).fold(Map.empty[String, Value]) { case (b, c, d) => append(cb.marshall(b), cc.marshall(c), cd.marshall(d)) }
}
val unmarshall =
for {
b <- cb.unmarshall
c <- cc.unmarshall
d <- cd.unmarshall
} yield to(b, c, d)
override def toString = s"Composite($cb, $cc, $cd)"
}
private final class Column4[A, B, C, D, E](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E])(to: (B, C, D, E) => A, from: A => Option[(B, C, D, E)]) extends Column[A] {
val marshall =
Marshaller[A] {
from(_).fold(Map.empty[String, Value]) { case (b, c, d, e) => append(cb.marshall(b), cc.marshall(c), cd.marshall(d), ce.marshall(e)) }
}
val unmarshall =
for {
b <- cb.unmarshall
c <- cc.unmarshall
d <- cd.unmarshall
e <- ce.unmarshall
} yield to(b, c, d, e)
override def toString = s"Composite($cb, $cc, $cd, $ce)"
}
private final class Column5[A, B, C, D, E, F](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E], cf: Column[F])(to: (B, C, D, E, F) => A, from: A => Option[(B, C, D, E, F)]) extends Column[A] {
val marshall =
Marshaller[A] {
from(_).fold(Map.empty[String, Value]) { case (b, c, d, e, f) => append(cb.marshall(b), cc.marshall(c), cd.marshall(d), ce.marshall(e), cf.marshall(f)) }
}
val unmarshall =
for {
b <- cb.unmarshall
c <- cc.unmarshall
d <- cd.unmarshall
e <- ce.unmarshall
f <- cf.unmarshall
} yield to(b, c, d, e, f)
override def toString = s"Composite($cb, $cc, $cd, $ce, $cf)"
}
private final class Column6[A, B, C, D, E, F, G](cb: Column[B], cc: Column[C], cd: Column[D], ce: Column[E], cf: Column[F], cg: Column[G])(to: (B, C, D, E, F, G) => A, from: A => Option[(B, C, D, E, F, G)]) extends Column[A] {
val marshall =
Marshaller[A] {
from(_).fold(Map.empty[String, Value]) {
case (b, c, d, e, f, g) =>
append(cb.marshall(b), cc.marshall(c), cd.marshall(d), ce.marshall(e), cf.marshall(f), cg.marshall(g))
}
}
val unmarshall =
for {
b <- cb.unmarshall
c <- cc.unmarshall
d <- cd.unmarshall
e <- ce.unmarshall
f <- cf.unmarshall
g <- cg.unmarshall
} yield to(b, c, d, e, f, g)
override def toString = s"Composite($cb, $cc, $cd, $ce, $cf, $cg)"
}
private def append(maps: KeyValue*): KeyValue = {
val builder = Map.newBuilder[String, Value]
maps.foreach { builder.++= }
builder.result
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy