I'm trying to map a DB row with more than 22 columns to a case class tree. I'd rather not using HList as I don't want to work with that API, and also for some exponential compilation time feedbacks that I've read somewhere...
I have read this thread answered by Stefan Zeiger: How can I handle a > 22 column table with Slick using nested tuples or HLists?
I've seen this test which shows how to define a custom mapping function and I'd like to do that:
def * = (
id,
(p1i1, p1i2, p1i3, p1i4, p1i5, p1i6),
(p2i1, p2i2, p2i3, p2i4, p2i5, p2i6),
(p3i1, p3i2, p3i3, p3i4, p3i5, p3i6),
(p4i1, p4i2, p4i3, p4i4, p4i5, p4i6)
).shaped <> ({ case (id, p1, p2, p3, p4) =>
// We could do this without .shaped but then we'd have to write a type annotation for the parameters
Whole(id, Part.tupled.apply(p1), Part.tupled.apply(p2), Part.tupled.apply(p3), Part.tupled.apply(p4))
}, { w: Whole =>
def f(p: Part) = Part.unapply(p).get
Some((w.id, f(w.p1), f(w.p2), f(w.p3), f(w.p4)))
})
The problem is that I can't make it!
I've tried by smaller steps.
class UserTable(tag: Tag) extends TableWithId[User](tag,"USER") {
override def id = column[String]("id", O.PrimaryKey)
def role = column[UserRole.Value]("role", O.NotNull)
def login = column[String]("login", O.NotNull)
def password = column[String]("password", O.NotNull)
def firstName = column[String]("first_name", O.NotNull)
def lastName = column[String]("last_name", O.NotNull)
//
def * = (id, role, login, password, firstName, lastName) <> (User.tupled,User.unapply)
//
def login_index = index("idx_user_login", login, unique = true)
}
It seems that when I call
(id, (firstName, lastName)).shaped
The type is ShapedValue[(Column[String], (Column[String], Column[String])), Nothing]
While this one seems to work fine
(id, firstName, lastName).shaped
The U type parameter is not Nothing
but as expected (String, String, String)
I don't really understand how all the Slick internals are working. Can someone explain me why I can't make my code work? Is there a missing import or something?
I guess I need to get a value of type
ShapedValue[(Column[String], (Column[String], Column[String])), (String, (String, String))]
but I don't know why it returns me Nothing
and don't really understand where these implicit Shape
parameters come from...
What I want is just to be able to easily split my column into 2 case classes
Thanks
Also, have the same problem with the 22 columns limitation, the test case helps very much. Not sure why the example code not working for you, the following code works fine for me,
case class UserRole(var role: String, var extra: String)
case class UserInfo(var login: String, var password: String, var firstName: String, var lastName: String)
case class User(id: Option[String], var info: UserInfo, var role: UserRole)
class UserTable(tag: Tag) extends Table[User](tag, "USER") {
def id = column[String]("id", O.PrimaryKey)
def role = column[String]("role", O.NotNull)
def extra = column[String]("extra", O.NotNull)
def login = column[String]("login", O.NotNull)
def password = column[String]("password", O.NotNull)
def firstName = column[String]("first_name", O.NotNull)
def lastName = column[String]("last_name", O.NotNull)
/** Projection */
def * = (
id,
(login, password, firstName, lastName),
(role, extra)
).shaped <> (
{ case (id, userInfo, userRole) =>
User(Option[id], UserInfo.tupled.apply(userInfo), UserRole.tupled.apply(userRole))
},
{ u: User =>
def f1(p: UserInfo) = UserInfo.unapply(p).get
def f2(p: UserRole) = UserRole.unapply(p).get
Some((u.id.get, f1(u.info), f2(u.role)))
})
def login_index = index("id_user_login", login, unique = true)
}