Search code examples
scalatransactionsslicktypesafe

Slick 3 Transactions with logic in Scala


I have a question about Slick 3 and Transactions

I have read the documentation

http://slick.typesafe.com/doc/3.1.0/dbio.html

and the other Slick 3 transaction questions

Slick 3 Transactions

Executing non-database actions in a transaction in Slick 3

But they didn't help me

I need to read some values from the database, run some logic in Scala, and then depending on the result, modify the database. I want the entire operation to be atomic.

My code looks something like this:

database.run(TableQuery[X].filter(blah).result).map { x =>
  database.run { 
    if( someLogicNotInSQL(x) ) 
      TableQuery[Y].insert(someFoo) 
    else 
      TableQuery[Y].insert(someBah)
  } 
}

How do I get the value of the query, run some logic in Scala, and then run another action (e.g. insert) all as one atomic transaction.

Thanks Peter


Solution

  • To run this in a transaction you will want to construct a single action that contains your queries and logic. Then run that action with a transaction.

    Modifying your example:

    import scala.concurrent.ExecutionContext.Implicits.global 
    
    val action = 
      tableQuery.filter(blah).result.flatMap { x =>
         if (someLogicNotInSql(x)) 
            tableQuery.insert(someFoo)
         else 
            tableQuery.insert(someBah)
      }
    

    flatMap requires as an argument a function from x to a DBIO[T]. It will sequence the two action together, allowing the second to use the result of the first.

    To run this combined action you''ll need a execution context. (Because your computation, if (someLogicNotInSql ..., will have to run on some thread somewhere, not Slick's internal execution context).

    You can wrap this combined action in a transaction and just call run once:

     val future = database.run(action.transactionally)