3

I'm using Slick 2.0 and I have the following User case class:

case class User(id: Option[Long], email: String, password: String)

class Users(tag: Tag) extends Table[User](tag, "user") {
  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def email = column[String]("email")
  def password = column[String]("password")

  def * = (id.?, email, password) <> ((User.apply _).tupled, User.unapply _)
}

and I have the following function getting a user via their database id:

def findOneById(id: Long) = DB.withSession { implicit session =>
  val result = (for {
                  u <- users if u.id === id
                } yield (u.id, u.email, u.password)).first
  User(Option(result._1), result._2, result._3)
}

Is there an easier way to convert the Seq response back result into the User case class?

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
threejeez
  • 2,314
  • 6
  • 30
  • 51
  • 1
    I briefly went over [http://slick.typesafe.com/doc/2.1.0/sql-to-slick.html](http://slick.typesafe.com/doc/2.1.0/sql-to-slick.html). can you try to use `.first` (I am guessing either instead of `.run` or after it). I never used slick but it seems it should be possible to tell it to return one record – benji Dec 23 '14 at 03:22
  • 1
    Is there a reason you aren't using mapped tables? http://slick.typesafe.com/doc/2.1.0/schemas.html#mapped-tables – Ryan Dec 23 '14 at 03:30
  • I'm pretty sure that's what I have. I've added the mapped table to my question. – threejeez Dec 23 '14 at 04:41
  • @benji using .first helps half way. I still get a tuple (Long, String, String), but at least it's no longer in a vector. I'm updating my question to reflect the change. – threejeez Dec 23 '14 at 04:49

3 Answers3

3

Ok, I found my answer. I got it in part from @benji and in part from this post: Converting scala.slick.lifted.Query to a case class.

Instead of using a for comprehension, the following returns an Option[User], which is exactly what I need:

def findOneById(id: Long):Option[User] = DB.withSession { implicit session =>
  users.filter(_.id === id).firstOption
}
Community
  • 1
  • 1
threejeez
  • 2,314
  • 6
  • 30
  • 51
2

For comprehension is easier in use with sql joins. Example:

def findOneById(id: Long) = DB.withSession { implicit session =>
    val query = for {
        u <- users if u.id === id
        t <- token if t.user_id = u.id && token.isActive === `A`
        } yield u    
    query.firstOption
}
Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
mgosk
  • 1,874
  • 14
  • 23
1

To convert the result to list of User case class, you can simply do

result.map(User.tupled)

However, that I will only work, if your data model is consitent. For example: Your user case class has id as optional where as it is a primary key in the DB which is wrong.

mohit
  • 4,968
  • 1
  • 22
  • 39
  • How is that wrong? The database is auto-generating the user id, and the only way I found for Slick to allow this to happen is to make the field optional and provide None when constructing and inserting new User objects. – threejeez Dec 23 '14 at 05:11