Problem:
I have a case class Foo
which can be anything.
I need a function to create a cypher query from this.
The signature of this new function should be
def createQueryString[T](t: T): String = ???
Example:
I have Foo
let's say having two members
case class Foo(x: Int, y: String)
I need it to be converted to cypher
CREATE (f:Foo { x: "1", y: "Hello" }) RETURN f
If I pass Foo(1, "Hello")
into the function createQueryString
mentioned above
createQueryString[Foo](Foo(1, "Hello"))
What have I tried so far?
I have tried using shapeless's Generic
and Aux
to achieve this
import shapeless._
case class Foo(x: Int, y: String)
def foo[T, HL <: HList](instance: T)(
implicit gen: Generic.Aux[T, HL]
): HL = {
gen.to(instance)
}
val myFoo = foo(Foo(1, "Hello"))
s"""CREATE (f:Foo { x: "${myFoo(0)}", y: "${myFoo(1)}" }) RETURN f"""
Is there any way I can use this foo(Foo(1, "Hello"))
to implement inside the createQueryString
mentioned above? I would want to basically pass types into this function down the road. Somewhat like
def createQueryString[T](t: T): String = {
val gen = foo(t) // to get the generic
s"""CREATE (t: T { x: "${gen(0)}", y: "${gen(1)}" }) RETURN t"""
}
Something like this. But by doing this I get the following error
Error:(77, 22) could not find implicit value for parameter gen: shapeless.Generic.Aux[T,HL]
val gen = foo(t) // to get the generic
Questions:
Aux
?x
and y
in the case class.You forgot implicit parameters (or context bounds).
Generic
can produce not only an HList
but also a Coproduct
. That's why if you loose bound <: HList
compiler doesn't know how to apply Generic
's Repr
to 0
, 1
.
Try
import shapeless.ops.hlist.At
import shapeless.nat._
def foo[T](instance: T)(
implicit gen: Generic[T]
): gen.Repr = {
gen.to(instance)
}
def createQueryString[T, L <: HList](t: T)(implicit
g: Generic.Aux[T, L],
at0: At[L, _0],
at1: At[L, _1]
): String = {
val gen = foo(t) // to get the generic
s"""CREATE (t: T { x: "${gen(0)}", y: "${gen(1)}" }) RETURN t"""
}
If you need labels x
, y
then you need LabelledGeneric
rather than Generic
.
If you have arbitrary number of parameters then you can transform an HList to desired form and then fold it to a string.
{ x: "1", y: "Hello" }
looks like a JSON. Look at Circe.