Search code examples
databasescalaplayframeworkslick

Scala Slick update column value


I'm using Slick with Play but am having some problems when trying to update a column value as it is not being updated, although I don't get any error back.

I have a column that tells me if the given row is selected or not. What I want to do is to get the current selected value (which is stored in a DB column) and then update that same column to have the opposite value. Currently (after many unsuccessful attempts) I have the following code which compiles and runs but nothing happens behind the scenes:

val action = listItems.filter(_.uid === uid).map(_.isSelected).result.map { selected =>
      val isSelected = selected.head
      println(s"selected before -> $isSelected")
      val q = for {li <- listItems if li.uid === uid} yield li.isSelected
      q.update(!isSelected)
    }

db.run(action)

What am I doing wrong (I am new to slick so this may not make any sense at all!)


Solution

  • This needs to be separate actions: one read followed by an update. Slick allows the composition of actions in a neat way:

    val targetRows = listItems.filter(_.uid === uid).map(_.isSelected)
    val actions = for {
      booleanOption <- targetRows.result.headOption
      updateActionOption = booleanOption.map(b => targetRows.update(!b))
      affected <- updateActionOption.getOrElse(DBIO.successful(0))
    } yield affected
    
    db.run(actions)
    

    Update:

    As a side note, RDBMSs usually facilitate constructs for performing updates in one database roundtrip such as updating a boolean column to its opposite value without needing to read it first and manually negate it. This would look like this in MySql for example:

    UPDATE `table` SET `my_bool` = NOT my_bool

    But, to my knowledge, the high-level slick API doesn't support this construct. hence the need for two separate database actions in your case. I, myself would appreciate it if somebody proved me wrong.