在Slick(Scala)中,如何重构这样的代码?

时间:2015-04-13 12:01:48

标签: scala playframework playframework-2.0 slick slick-2.0

我看到这样的代码:

trait LoginInfoRepoImpl extends LoginInfoRepo {

  def loginInfoRepository = new LoginInfoRepository {
    private val loginInfoTable = TableQuery[LoginInfoTable]

    // return a LoginID
    def save(userLoginInfo: userLoginInfo): Future[userLoginID] = Future {
      val newRecord = DB.withSession { implicit session =>
        loginInfoTable.filter(
          l => l.userID === userLoginInfo.userID &&
          (l.deviceID === userLoginInfo.deviceID || (l.deviceID.isEmpty && userLoginInfo.userID.isEmpty))).list.headOption.fold {
          val newSubID = loginInfoTable.filter(l => l.userID === userLoginInfo.userID).sortBy(_.subID.desc).take(1).map(_.subID).list.headOption.getOrElse(0) + 1
          (loginInfoTable returning loginInfoTable) += LoginInfoRecord(userLoginInfo.userID, newSubID, userLoginInfo.deviceID, userLoginInfo.userAgent, getCurrentTime)
        } { l =>
          // to do : update time
          val q = for (l <- loginInfoTable if l.userID === userLoginInfo.userID && ((l.deviceID === userLoginInfo.deviceID)
            || (l.deviceID.isEmpty && userLoginInfo.userID.isEmpty)))
            yield l.lastLoginTime
          q.updateReturning(loginInfoTable.map(identity), getCurrentTime).head
        }
      }
      userLoginID(newRecord.userID, newRecord.subID.toString)
    }

  }
}

对我来说这看起来有些怪异。我发现很多东西都挤在一条线上。另外,我发现l.deviceID的类型为Column[Option[String]],而userLoginInfo.deviceID的类型为Option[String],如果它们都是None,则它们不相等。因此,l.device.isEmpty看起来是必要的..

有人有关于如何重构这些代码的建议吗?谢谢!

1 个答案:

答案 0 :(得分:0)

首先:更好的缩进和打破长线。

特定于Slick:从withSession块中提取查询并将其重用于共享逻辑。使用firstOption而不是.list.headOption。

旁注:由于您是基于旧ID生成ID,因此您可能希望使用事务或使用数据库提供的更有效的方法。

trait LoginInfoRepoImpl extends LoginInfoRepo {
  def loginInfoRepository = new LoginInfoRepository {
    private val loginInfoTable = TableQuery[LoginInfoTable]

    // return a LoginID
    def save(userLoginInfo: userLoginInfo): Future[userLoginID] = Future {
      val userLoginInfoQuery = loginInfoTable.filter(l => l.userID === userLoginInfo.userID)
      val deviceLoginInfoQuery = userLoginInfoQuery.filter(
        l =>
          l.deviceID === userLoginInfo.deviceID ||
          (
            l.deviceID.isEmpty && userLoginInfo.userID.isEmpty
          )
        )
      val subIdQuery = userLoginInfoQuery.sortBy(_.subID.desc).map(_.subID)
      val newRecord = DB.withTransaction{ implicit session =>
        deviceLoginInfoQuery
          .firstOption
          .fold {
            val newSubID = subIdQuery.firstOption.getOrElse(0) + 1
            val newLoginInfo = LoginInfoRecord(userLoginInfo.userID, newSubID, userLoginInfo.deviceID, userLoginInfo.userAgent, getCurrentTime)
            (loginInfoTable returning loginInfoTable) += newLoginInfo
          }( _ =>
            // to do : update time
            deviceLoginInfoQuery
              .map(_.lastLoginTime)
              .updateReturning(loginInfoTable.map(identity), getCurrentTime)
              .head
          )
      }
      userLoginID(newRecord.userID, newRecord.subID.toString)
    }

  }
}