Scala、Slick、Cats - 如何使用 OptionT 映射不同的 SQL 错误?

问题描述 投票:0回答:1

我有一个在数据库上运行的简单

slick
查询:

def method(): Future[Either[Error, MyCustomDTO]] = 
OptionT(database.run(query))
  .map(MyCustomDTO(_))
  .toRight(dataNotFound())
  .value

问题出在

.toRight
。我想将其映射到不同的错误,具体取决于数据库返回的内容。例如

case FOREIGN_KEY_CONSTRAINT_VIOLATION.toString => constraintError()
case UNIQUE_CONSTRAINT_VIOLATION.toString => uniqueError()
case _ => dataNotFound()

我尝试在

match case
中执行
.toRight()
,但它不起作用:

.toRight(error => error.asInstanceOf[PSQLException].getSQLState match { .... })

我想知道以正确的方式在这里映射不同错误的最佳可能性是什么?

scala slick scala-cats
1个回答
0
投票

看看

toRight(...)

的签名
def toRight[L](left: => L)(implicit F: Functor[F]): EitherT[F, L, A] =
  EitherT(cata(Left(left), Right.apply))

def toRightF[L](left: => F[L])(implicit F: Monad[F]): EitherT[F, L, A] =
  EitherT(cataF(F.map(left)(Left.apply[L, A]), a => F.pure(Right(a))))

这两个参数都采用名称参数 - 换句话说,它们是

() => ...
的特殊语法,其中为您插入定义中的
() => ...
和应用程序中的
...()
。为什么?因为在
toLeft
中的
toRight
/
OptionT
上,假设您正在处理由
Option
表示的错误类型 - 即
None
。由于不需要传递
_: None.type =>
,因此它使用按名称参数。

如果你想处理错误,你必须在

F[A]
内部处理它 - 通过提供正确的类型类(
ApplicativeError[F, Throwable]
/
MonadError[F, Throwable]
),这将允许调用
handleError
/
handleErrorWith
/
redeem

// F: ApplicativeError[F, Throwable]
// fa: F[MyCustomDTO]
F.redeem(fa)(a => Right(a), error => Left(error match { ... }))

// or with extension methods
fa.redeem(a => Right(a), error => Left(error match { ... }))

因为你的

F
似乎是
Future
,而且因为你把它包裹在
OptionT
中,我想如果你这样做的话效果会更好:

OptionT(database.run(query))
  .map(MyCustomDTO(_).asRight[Error])
  .getOrElse(dataNotFound().asLeft[MyCustomDTO])
  .handleWith { error =>
    Left(error.asInstanceOf[PSQLException].getSQLState match {
      ...
    })
  }
© www.soinside.com 2019 - 2024. All rights reserved.