Insert or get - Slick 3

128 views
Skip to first unread message

aguf...@gmail.com

unread,
Aug 30, 2015, 1:30:54 AM8/30/15
to Slick / ScalaQuery
Hi guys, I was trying to insert if not exists, and get the row if it does.
I come up with this:

def saveOrGet(u: User) = (for {
  userGet <- get(u.name).map(r => (r.id, r.active)).result.headOption
  id <- save(u) if userGet.isEmpty
} yield {
  schoolGet match {
    case Some((id, active)) => (User(Some(id), u.name, active), false)
    case None               => (User(Some(id), u.name, u.active), true)
  }
}).transactionally


private def get(name: String) = users.filter(_.name === name).take(1)
   
private def save(u: User) = users returning users.map(_.id) += u


But it always insert the row even if the name already exists.

Can you help me?

Regards

ma...@alessandrogarzaro.net

unread,
Sep 2, 2015, 1:09:05 PM9/2/15
to Slick / ScalaQuery
Hi and sorry in advance for my poor worded reply :)

What you are doing wrong, in my opinion, is that you are doing a isEmpty test 
against an Option, that might be Some() or None but won't be empty so you need
to check in a different way if you have already, or not, a name in the database.

Disclaimer:
I used the Hello Slick 3 seed from Typesafe Activator so the User class it's slighty 
different (user.id is an Int and it's missing the active member, but it should be easy 
to be changed to your needs). I've attached the source file used to make the tests
so you can check it aswell.

My version of the code is something like this:

def saveOrGet(u: User) = (for {
userGet <- get(u.name)
  result  <- userGet.map( DBIO.successful ).getOrElse( save(u) )
} yield
result match {
case userId:Int => User( u.name, Some(userId) )
case user:User => user
}).transactionally

private def get(name: String) = users.filter( _.name === name ).result.headOption


private def save(u: User) = users returning users.map( _.id ) += u

I've changed the get to return Some(User) or None, then it's chained with the 
save action so if the get is successful it returns a result of type User, otherwise 
it returns an id. In the yield block I run a match to see if I got a new id (hence a 
new user in the db) or an existing user so I can compose always return a User.

Regards,
Alessandro.
CaseClassMapping.scala

aguf...@gmail.com

unread,
Sep 2, 2015, 8:49:51 PM9/2/15
to Slick / ScalaQuery
EXCELLENT!

After two weeks, it finally worded!
Thank you very much!
Even though I don't understand yet what DBIO.successful does, the code work properly!

aguf...@gmail.com

unread,
Sep 21, 2015, 9:41:56 PM9/21/15
to Slick / ScalaQuery
Hi again, I was wondering how can I expand this query by inserting another row in another table using the recently added user's ID.

For example:

def saveOrGet(u: User) = (for {
  userGet <- get(u.name)
  result  <- userGet.map( DBIO.successful ).getOrElse( save(u) )
} yield
 result match {
  case userId:Int => {
    // another_insert(userId)

    User( u.name, Some(userId) )
  }
  case user:User  => user
}).transactionally

def another_insert(id: Int) = {
  another_table += id
}

Reply all
Reply to author
Forward
0 new messages