forked from tpolecat/doobie
-
Notifications
You must be signed in to change notification settings - Fork 0
/
catchsql.scala
71 lines (59 loc) · 2.44 KB
/
catchsql.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// Copyright (c) 2013-2020 Rob Norris and Contributors
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT
package doobie.util
import cats.ApplicativeError
import cats.syntax.applicativeError.*
import cats.syntax.apply.*
import cats.syntax.either.*
import cats.syntax.functor.*
import doobie.enumerated.SqlState
import java.sql.SQLException
/**
* Module of additional combinators for `ApplicativeError`, specific to
* `SQLException`.
*/
object catchsql {
/** Like `attempt` but catches only `SQLException`. */
def attemptSql[M[_], A](ma: M[A])(implicit F: ApplicativeError[M, Throwable]): M[Either[SQLException, A]] =
ma.map(_.asRight[SQLException]).recover {
case e: SQLException => e.asLeft
}
/** Like `attemptSql` but yields only the exception's `SqlState`. */
def attemptSqlState[M[_], A](ma: M[A])(
implicit ev: ApplicativeError[M, Throwable],
): M[Either[SqlState, A]] =
attemptSql(ma).map(_.leftMap(e => SqlState(e.getSQLState)))
def attemptSomeSqlState[M[_], A, B](ma: M[A])(f: PartialFunction[SqlState, B])(implicit
AE: ApplicativeError[M, Throwable],
): M[Either[B, A]] =
ma.map(_.asRight[B]).recoverWith {
case e: SQLException =>
f.lift(SqlState(e.getSQLState)).fold(AE.raiseError[Either[B, A]](e))(b => AE.pure(b.asLeft))
}
/** Executes the handler, for exceptions propagating from `ma`. */
def exceptSql[M[_], A](ma: M[A])(handler: SQLException => M[A])(implicit F: ApplicativeError[M, Throwable]): M[A] =
ma.recoverWith {
case e: SQLException => handler(e)
}
/** Executes the handler, for exceptions propagating from `ma`. */
def exceptSqlState[M[_], A](ma: M[A])(handler: SqlState => M[A])(
implicit ev: ApplicativeError[M, Throwable],
): M[A] =
exceptSql(ma)(e => handler(SqlState(e.getSQLState)))
/**
* Executes the handler where defined, for exceptions propagating from `ma`.
*/
def exceptSomeSqlState[M[_], A](ma: M[A])(pf: PartialFunction[SqlState, M[A]])(implicit
AE: ApplicativeError[M, Throwable],
): M[A] =
exceptSql(ma) { e =>
pf.lift(SqlState(e.getSQLState)).fold(AE.raiseError[A](e))(a => a)
}
/**
* Like "finally", but only performs the final action if there was an
* exception.
*/
def onSqlException[M[_], A, B](ma: M[A])(action: M[B])(implicit F: ApplicativeError[M, Throwable]): M[A] =
exceptSql(ma)(e => action *> F.raiseError(e))
}