1
votes

I want to update a certain column in row only if row has a valid data. Being specific: I have a table with Event which stores start, stop and isActive flag. I would like some Events activate by setting isActive to true, however I need to check if start and stop dates are valid. model:

 case class Event {start:DateTime, stop:DateTime, isActive:Boolean}

my validation method signature :

validateEvent(ev: Event): Boolean

My first approach:

def activateEv() = Action.async(parse.json) { request => { ... val ev = db.run(dao.findEvById(poid, uid)) val ret = ev.flatMap { case st: Option[Event] => if (validateEvent(st.get)) { db.run(dao.updateActivity(poid, true).map { case 0 => false case other => true } } else Future(false) } ... } }

I believe that it is not the way how this problem should be addressed. Could you advice ? Maybe only one db.run will be sufficient ?

1

1 Answers

2
votes

This can be achieved in a single db.run using combinators (e.g. flatMap) on DBIOAction objects. Assuming that your dao methods look like that:

case object dao {
  def findEvById(poid: Int, uid: Int): DBIOAction[Option[Event], NoStream, Effect.Read] = ???

  // In your case `updateActivity` returns an `Int` and you're mapping it to a `Boolean`.
  // That mapping could be placed here, so `updateActivity` would return `Boolean` now.
  def updateActivity(poid: Int, bool: Boolean): DBIOAction[Boolean, NoStream, Effect.Write] = ???
}

This is how we can achieve the thing you're looking for:

...
val action = dao.findEvById(poid, uid).flatMap {
  case Some(event) if validateEvent(event) => dao.updateActivity(poid, true)
  case _ => DBIO.successful(false)
}.transactionally

db.run(action)
...

As you see we have a transaction here, which would make a selection followed by an update (only if the event is valid). Moreover, that whole select then update action could be a separate method in your dao.