根据可选值编写更新查询

Compose update query based on optional values

下面的函数有一个 UUID 参数和两个可选参数。根据两个可选参数的状态将决定它们是否包含在更新查询中。

    def updateChunkState(chunkId: UUID, state: ChunkState, comment: Option[String], sourceLanguage: Option[String]): Either[ChunkNotFoundError, Unit] = {
      
      val result = (comment, sourceLanguage) match {
        case (c: Some[String], s: Some[String]) => {
          val query = ChunkTable.query.filter(_.id === chunkId.toString).map(c => (c.state, c.comment, c.sourceLanguage))
          exec(query.update(state, comment, sourceLanguage)) 
        }
        case (c: Some[String], None) => { 
          val query = ChunkTable.query.filter(_.id === chunkId.toString).map(c => (c.state, c.comment))
          exec(query.update(state, comment)) 
        }
        case (None, s: Some[String]) => {
          val query = ChunkTable.query.filter(_.id === chunkId.toString).map(c => (c.state, c.sourceLanguage))
          exec(query.update(state, sourceLanguage)) 
        }
        case (None, None) => {
          val query = ChunkTable.query.filter(_.id === chunkId.toString).map(c => (c.state))
          exec(query.update(state)) 

        }
      }
      result match {
        case 0 => Left(ChunkNotFoundError(chunkId))
        case n if n > 0 => Right(())
      } 

    }

我相信应该有一种方法可以让我的 query/update 比我上面的蛮力尝试更优雅一点,如果有人能启发我,我将不胜感激。

我认为你在 atm 上的做法很好。 4场比赛没有出路。也许让它更优雅的一种方法是将重复代码收集到一个地方,即。您可以在一个地方调用 exec(query.update(...)) 而不是在 4 个地方调用它。在这里我只是将其称为字符串列表,我不知道该函数如何使用可变数量的参数。而不是在 4 个不同的地方过滤它,你可以在开始模式匹配之前过滤一次。只是让它更容易阅读,因为它不是一大段代码。

如果您不使用匹配的元组变量,则无需为它们命名,即 c 和 s。而且也不需要类型,你知道它是来自函数签名的字符串。在那种情况下(我不需要变量)我更喜欢 Some(_),如果你匹配正确的方式,从 (Some, Some) 到 (None, None),使用 _ (通配符) 用于 None 情况,_ 用于 (None, None) 情况

我列出了您用于 query.update() 的所有参数并将它们放入列表中。在 Some() 中包装状态并使用展平来删除 Nones。然后使用 _* 运算符将这些应用于函数。

我认为代码就这样没问题,但你可以像这样删掉 10 行。

def updateChunkState(chunkId: UUID, state: ChunkState, comment: Option[String], sourceLanguage: Option[String]): Either[ChunkNotFoundError, Unit] = {

    val updateParams = List(Some(state), comment, sourceLanguage).flatten

    val queryFiltered = ChunkTable.query.filter(_.id === chunkId.toString)

    val query = (comment, sourceLanguage) match {
      case (Some(_), Some(_)) => queryFiltered.map(c => (c.state, c.comment, c.sourceLanguage))
      case (Some(_), _) => queryFiltered.map(c => (c.state, c.comment))
      case (_, Some(_)) => queryFiltered.map(c => (c.state, c.sourceLanguage))
      case _ => queryFiltered.map(c => (c.state))
    }

    exec(query.update(updateParams:_*)) match {
      case 0 => Left(ChunkNotFoundError(chunkId))
      case n if n > 0 => Right(())
    }