Search code examples
scalaslick

Slick 3.0 Update Row Based on a Condition


I have the following method that actually updates the database row against a table. It first checks for an entry if it exists with a certain condition and only if it exists, it updates the corresponding row. So effectively, there are two calls being made to the database. I would like to avoid having two calls sent to the database. So here is the code:

  def confirmUserRegistration(hash: String) = async {
    val query = UserRegistrationTable.registrationForHash(hash)
    val isRowAvailable = await(database.run(query.result.headOption))
    if (isRowAvailable.isDefined) {
      // do the update
    } else {
    // do nothing and return
    }
  }

The UserRegistrationTable.registrationForHash(hash) query looks like this:

  object UserRegistrationTable {

    val all = TableQuery[UserRegistrationTable]

    val registrationForHash = (hash: String) => {
      all.filter(_.registrationHash === hash)
    }
  }

So how can I optimize my service to issue only one call to the database?

EDIT: Updated with the feedback given by the post below:

Here is how my method looks:

  def confirmUserRegistration(hash: String) = async {
    val query = {
      UserRegistrationTable.registrationForHash(hash)
        .map(_.hasUserConfirmed)
        .update(true)
    }

    val isUpdated: Int = await(database.run(query))

  }

Solution

  • Just use the following update:

    val updateOperation: DBIO[Int] = all
        .filter(_.registrationHash === hash)
        .map(u => (u.field1, u.field2, u.field3))
        .update((newValue1, newValue2, newValue3))
    

    Notice that updateResult above is DBIO containing Int - being the number of updated rows.

    So you can do:

    db.run(updateOperation).map { updatedRows =>
         if(updatedRows >= 0) {
             // at least one row was affected, return something here
         } else {
             // nothing got updated, return something here
         }
    }
    

    In case you wanted to updated whole row you could use your case class but I doubt that is what you want:

    val userRegistration: UserRegistrationCaseClass = ...
    
    val updateOperation: DBIO[Int] = all
        .filter(_.registrationHash === hash)
        .update(newUserRegistration)