New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update FieldMapper to use an implicit Printer #105

Closed
fedefernandez opened this Issue Oct 23, 2017 · 0 comments

Comments

Projects
None yet
1 participant
@fedefernandez
Contributor

fedefernandez commented Oct 23, 2017

A Printer is just a trait that transforms a String into a String, as shown here:

trait Printer {
def print(name: String): String
}

We currently have a FieldMapper that stores a column name and provides a method for returning the value for this column as a ByteBuffer:

abstract class FieldMapper(val name: String) {
def serialize[M[_]](implicit E: MonadError[M, Throwable]): M[ByteBuffer]
}

We need to refactor it to make use of an implicit Printer instead of using the actual case class field name:

We also need to adapt Unit Tests to this new implementation. The tests are located here:

"ByteBufferMapper.map" should {
"map the fields for a regular case class" in {
import FieldListMapper._
import cats.instances.try_._
check {
forAll { a: A =>
val mapper: ByteBufferMapper[A] = ByteBufferMapper[A]
val mapperList: List[FieldMapper] = mapper.map(a)
mapperList.size == 3 &&
mapperList.head.serialize == intCodec.serialize(a.a1) &&
mapperList(1).serialize == stringCodec.serialize(a.a2) &&
mapperList(2).serialize == booleanCodec.serialize(a.a3)
}
}
}
"map the fields for a case class with another embedded case class and his decoder" in {
import FieldListMapper._
implicit val decoder: ByteBufferCodec[B] = new ByteBufferCodec[B] {
val Regex: Regex = "(\\d+);(.+)".r
override def deserialize[M[_]](bytes: ByteBuffer)(
implicit E: MonadError[M, Throwable]): M[B] =
E.flatMap(stringCodec.deserialize(bytes)) {
case Regex(v1, v2) => E.pure(B(v1.toLong, v2))
case _ => E.raiseError[B](new RuntimeException("Bad serialized value"))
}
override def serialize[M[_]](value: B)(
implicit E: MonadError[M, Throwable]): M[ByteBuffer] =
stringCodec.serialize(value.b1 + ";" + value.b2)
}
import cats.instances.try_._
check {
forAll { c: C =>
val mapper: ByteBufferMapper[C] = ByteBufferMapper[C]
val mapperList: List[FieldMapper] = mapper.map(c)
mapperList.size == 2 &&
mapperList.head.serialize == stringCodec.serialize(c.c1) &&
mapperList(1).serialize == decoder.serialize(c.c2)
}
}
}
"map the fields for a case class with another embedded case class" in {
import FieldMapperExpanded._
import cats.instances.try_._
check {
forAll { c: C =>
val mapper = ByteBufferMapper[C]
val mapperList: List[FieldMapper] = mapper.map(c)
mapperList.size == 3 &&
mapperList.head.serialize == stringCodec.serialize(c.c1) &&
mapperList(1).serialize == longCodec.serialize(c.c2.b1) &&
mapperList(2).serialize == stringCodec.serialize(c.c2.b2)
}
}
}
}

An example of the behavior we are looking for can be found here:

implicit def hconsFromReader[K <: Symbol, V, L <: HList](
implicit
witness: Witness.Aux[K],
codec: ByteBufferCodec[V],
grT: FromReader[L],
printer: Printer): FromReader[FieldType[K, V] :: L] =
new FromReader[FieldType[K, V] :: L] {
override def apply[M[_]](reader: ByteBufferReader)(
implicit ME: MonadError[M, Throwable]): M[FieldType[K, V] :: L] = {
val newName = printer.print(witness.value.name)
ME.flatMap(reader.read(newName)) { byteBuffer =>
ME.map2(codec.deserialize(byteBuffer), grT(reader)) {
case (result, l) => new FieldBuilder[K].apply(result) :: l
}
}
}
}

@fedefernandez fedefernandez changed the title from Update FieldMapper to use a printer implicit to Update FieldMapper to use an implicit Printer Oct 26, 2017

@fedefernandez fedefernandez added the spree label Oct 26, 2017

@fedefernandez fedefernandez self-assigned this Nov 6, 2017

@fedefernandez fedefernandez closed this in #111 Nov 6, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment