Search code examples
scalaslickslick-3.0

Conditionally running Slick statements in a for comprehension


Given the following Slick code:

   val doUpdate = true

   val table1 = TableQuery[Table1DB]
   val table2 = TableQuery[Table2DB]
   val table3 = TableQuery[Table3DB]

   val action = (for {
          _ <- table1.filter(_.id === id).update(table1Record)
          _ <- table2.filter(_.id === id).update(table2Record)
          _ <- table3.filter(_.id === id).update(table3Record)
     } yield ()).transactionally

What I need is to update table2 and table3 ONLY if the variable doUpdate is true. This is my attempt:

   val action = (for {
          _ <- table1.filter(_.id === id).update(table1Record)
          _ <- table2.filter(_.id === id).update(table2Record)
               if (doUpdate == true)
          _ <- table3.filter(_.id === id).update(table3Record)
               if (doUpdate == true)
     } yield ()).transactionally

This compiles, but when I run it I get the following error Action.withFilter failed. How to add the condition?


Solution

  • As you notices if you use if inside a for it will call withFilter underneath. In case of pipelines (DBIO, Futures, Tasks) that filtering boils down to whether or not continue with a pipeline (happy path) or fail it (generating Failure or similar).

    If all you want is to update, then you can go with the if road and recover the Future. However, it would we ugly, since depending on how you write the case it might also recover from errors you would like to be informed about.

    Alternative is to simply use if-else to provide a different DBIOAction:

    (for {
      _ <- {
        if (doUpdate) conditionalAction.map(_ => ())
        else DBIOAction.successful(())
      }
    } yield ()).transactionally
    

    In your case it could look something like:

    val action = (for {
      _ <- table1.filter(_.id === id).update(table1Record)
      _ <- {
        if (doUpdate) DBIOAction.seq(
          table2.filter(_.id === id).update(table2Record),
          table3.filter(_.id === id).update(table3Record)
        )
        else DBIOAction.successful(())
      }
    } yield ()).transactionally