In Slick 3.0, how do I simplify the nested `db.run`?

I am using Slick 3.0 and the following are my codes:

def registerMember(newMember: TeamMember): Future[Long] = {

  db.run(
    teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption
  ).flatMap {
    case None => Future(-1)
    case _ => db.run(
      (teamProfileTable returning teamProfileTable.map(_.staffID)) += newMember.toTeamRecord
    )
  }
}

      

It might look okay. But when there are more callback layers, the codes can become hard to read. I tried to simplify the codes with for-expression

or andThen

.. But because of the pattern matching part I can use flatMap

to implement this.

Does anyone have any ideas on how to refactor this?

+3


source to share


2 answers


I think it should be good to understand, you just need to conditionally handle the Option

result of the former Future

. Something like this should work (note that I did not compile the check):

def registerMember(newMember: TeamMember): Future[Long] = {

  for{
    r1Opt <- db.run(teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption
    r2 <- r1Opt.fold(Future.successful(-1L))(r1 => db.run((teamProfileTable returning teamProfileTable.map(_.staffID)) += newMember.toTeamRecord)
  } yield r2

}

      

On the right side, fold

you can see that I have access to the result of the first one Future

, if it was Some

(like r1

).



I would even take it even further and create separate methods for steps to understand to clean things up, like:

def registerMember(newMember: TeamMember): Future[Long] = {
  def findMember = 
    db.run(teamProfileTable.filter(u => u.ID === newMember.ID).result.headOption

  def addMember(r1Opt:Option[TeamMember]) = {
    r1Opt.fold(Future.successful(-1L)){r1 =>
      db.run((teamProfileTable returning teamProfileTable.map(_.staffID)) += 
        newMember.toTeamRecord)
    }
  }

  for{
    r1Opt <- findMember
    r2 <- addMember(r1Opt)
  } yield r2

}

      

+2


source


Another approach to simplifying nested db.runs in Slick 3.0, when a query spans two tables, might be to combine the queries into a single query. Joining and Zipping . However, the OP seems to have a slightly rarer case of nested queries in the same table, so this approach may not be practical in this particular case.



val query = slickLoginInfos join slickUserLoginInfos on 
   ((l,ul) => l.id === ul.loginInfoId) 
db.run((for { (l, ul) <- query } yield (ul)).result.headOption)

      

0


source







All Articles