Last active
November 1, 2018 00:34
-
-
Save tkroman/1139b117b76a74a463a11aef8708fbe1 to your computer and use it in GitHub Desktop.
cassandra writer typeclass with support for field annotations to customize column names using shapeless
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.annotation.StaticAnnotation | |
import com.datastax.driver.core.BoundStatement | |
import shapeless._ | |
import shapeless.labelled._ | |
import shapeless.ops.hlist.Zip | |
case class ColName(v: String) extends StaticAnnotation | |
sealed trait CRow[A] { | |
def write(a: A, s: BoundStatement): BoundStatement | |
} | |
object CRow { | |
implicit val hnil: CRow[HNil] = new CRow[HNil] { | |
override def write(a: HNil, s: BoundStatement): BoundStatement = s | |
} | |
type Cell[A, B, C] = (FieldType[A, B], C) | |
implicit def hcons[FN <: Symbol, | |
H, | |
T <: HList, | |
CN <: Option[ColName]](implicit | |
fieldName: Witness.Aux[FN], | |
writeTail: CRow[T], | |
writeHead: CCell[H]): CRow[Cell[FN, H, CN] :: T] = { | |
new CRow[Cell[FN, H, CN] :: T] { | |
override def write(a: Cell[FN, H, CN] :: T, | |
s: BoundStatement): BoundStatement = { | |
val (value, colName) = a.head | |
val columnName: String = colName.map(_.v).getOrElse(fieldName.value.name) | |
writeHead.write(value, columnName, s) | |
writeTail.write(a.tail, s) | |
} | |
} | |
} | |
implicit def mkCrow[A, | |
GenRow <: HList, | |
Annots <: HList, | |
KeyList <: HList, | |
KeysToAnns <: HList, | |
GToAnns <: HList](implicit | |
gen: LabelledGeneric.Aux[A, GenRow], | |
anns: Annotations.Aux[ColName, A, Annots], | |
gaZipper: Zip.Aux[GenRow :: Annots :: HNil, GToAnns], | |
gcrow: Lazy[CRow[GToAnns]]): CRow[A] = { | |
new CRow[A] { | |
override def write(a: A, s: BoundStatement): BoundStatement = { | |
val genericRow: GToAnns = gen.to(a).zip(anns()) | |
gcrow.value.write(genericRow, s) | |
} | |
} | |
} | |
def apply[A](implicit crow: CRow[A]): CRow[A] = crow | |
} | |
sealed trait CCell[A] { | |
def write(a: A, n: String, s: BoundStatement): BoundStatement | |
} | |
object CCell { | |
implicit val int: CCell[Int] = new CCell[Int] { | |
override def write(a: Int, | |
n: String, | |
s: BoundStatement): BoundStatement = s.setInt(n, a) | |
} | |
implicit val text: CCell[String] = new CCell[String] { | |
override def write(a: String, | |
n: String, | |
s: BoundStatement): BoundStatement = s.setString(n, a) | |
} | |
implicit def opt[A: CCell]: CCell[Option[A]] = new CCell[Option[A]] { | |
override def write(a: Option[A], | |
n: String, | |
s: BoundStatement): BoundStatement = { | |
a match { | |
case Some(x) => implicitly[CCell[A]].write(x, n, s) | |
case None => s.setToNull(n) | |
} | |
} | |
} | |
} | |
object Main { | |
case class Foo(@ColName("YES") x: Int, y: String, z: Option[Int]) | |
def main(args: Array[String]): Unit = { | |
val foo = Foo(1, "2", None) | |
val crow: CRow[Foo] = CRow[Foo] | |
crow.write(foo, null) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment