在没有显式匹配的情况下转换 Doobie ConnectionIO[Option[Int]]

Transforming Doobie ConnectionIO[Option[Int]] without explicit match

我有一个 ConnectionIO[Option[Int]] 并映射到 Option 以生成带有查询 Some[Int]ConnectionIO[Option[String]] 否则保留 Nones. I was able to do this with aforcomprehension and a匹配`:

def findWidgetByOwner(name: String): ConnectionIO[Option[String]] = for {
    opt <- sql"SELECT owner_id FROM owners WHERE name = $name".query[Int].option
    widget <- opt match {
        case None => None.pure[ConnectionIO]
        case Some(id) => sql"SELECT widget_name FROM widgets WHERE owner_id = $id".query[String].option
    }
} yield widget

我知道我被 ConnectionIO 容器绊倒了,但我找不到更清晰的映射方法来将 ConnectionIO[Option[Int]] 转换为 ConnectionIO[Option[String]]

使用 SQL 而不是 scala 加入会更干净:

def findWidgetByOwner(name: String): ConnectionIO[Option[String]] = 
  sql"""
    SELECT widgets.widget_name FROM widgets WHERE owner_id = $id
    INNER JOIN owners ON widgets.owner_id = owners.owner_id
    WHERE owners.name = $name
  """.query[Int].option

但是如果你想清理原来的,sequence 的一些咒语可能会起作用(未测试):

import cats._, cats.data._, cats.implicits._

...
widget <- opt.map {id => 
  sql"SELECT widget_name FROM widgets WHERE owner_id = $id".query[String].unique
}.sequence

注意:你必须把query[String].option改成.query[String].unique否则widget就变成了Option[Option[String]] 如果小部件查询可以为空,可能是可取的,但最后需要一个 .flatten