Hello!
Story:
The slick lib has a strange method to transform back and forth between columns and case-classes (actually its not so strange if you get used to it). I wanted to create a new trait, which can add createdBy createdAt, updatedBy updatedAt fields to a random table without a lot of refactor/code rewrite.
Problem:
I need to create a func like this:
def * = (a, b, c) <> (A.tuppled, A.unapply)
where a
is sth like a Rep[String]
(I can use def * = (a :: b :: c :: HNil).mappedWith(Generic[A])
too with slickless.)
My idea:
I have 2 tuples (one for the audit fields, and one for the concrete DBO).
val tuple1 = (1, 3, "asd")
val tuple2 = ("dsa", 5L, 2.3, 5.7)
I can transform them to satisfy the left side of the <>
val listOfTuples = tuple1 :: tuple2 :: HNil
//or
val hlist1 = tuple1.productElements
val hlist2 = tuple2.productElements
val listOfLists = hlist1 :: hlist2 :: HNil
I can create the case-classes too (the type of B
will be the actual DBO):
case class Foo(a: Int, b: Int, c: String)
case class Bar(d: String, e: Long, f: Double, g: Double)
case class Both[B](f: Foo, b: B)
And now, I need a Generic[Both[Bar]]
which is deeper than the default generated code.
val g = Generic[Both[Bar]] //Foo :: Bar :: HNil
val needed = DeeperGeneric[Both[Bar]] //(Int :: Int :: String :: HNil) :: (String :: Long :: Double :: Double :: HNil) :: HNil
So basically I want a DeeperGeneric implementation if it is possible (I need to transform from-to.)
The closest I get to this problem is sth like:
val generic = Generic[Bar]
def * = (auditTuple :: fieldTuple :: HNil).mappedWith(new LessGeneric(generic.to, generic.from))
Which is not as bad, but still I think there is a better way…
Full scratch (I want to factor out the T
from this code):
import shapeless.Generic.Aux
import shapeless._
import syntax.std.tuple._
import scala.reflect.ClassTag
val tuple1 = (1, 3, "asd")
val tuple2 = ("dsa", 5L, 2.3, 5.7)
val listOfTuples = tuple1 :: tuple2 :: HNil
val hlist1 = tuple1.productElements
val hlist2 = tuple2.productElements
val listOfLists = hlist1 :: hlist2 :: HNil
case class Foo(a: Int, b: Int, c: String)
case class Bar(d: String, e: Long, f: Double, g: Double)
case class Both[B](f: Foo, b: B)
class LessGeneric[B, T](to: B => T, from: T => B) extends Generic[Both[B]] {
type Repr = genf.Repr :: T :: shapeless.HNil
val genf = Generic[Foo]
/** Convert an instance of the concrete type to the generic value representation */
def to(t : Both[B]) : Repr = {
genf.to(t.f) :: to(t.b) :: HNil
}
/** Convert an instance of the generic representation to an instance of the concrete type */
def from(r : Repr) : Both[B] = {
Both(
genf.from(r.head),
from(r.tail.head)
)
}
}
val g3 = Generic[Bar]
val lessGen = new LessGeneric(g3.to, g3.from)
lessGen.from(listOfLists)
Any idea, maybe a concrete proof that it can’t be done would be appreciated. (I dropped the idea of using this bcs of other business reasons, but I still want to know the answer if there is any )
EDIT: Tried to force the formatter to use scala code-blocks.