Skip to content

Instantly share code, notes, and snippets.

@gakuzzzz
Last active May 22, 2020 02:19
Show Gist options
  • Save gakuzzzz/f3df2c8073410fb5e8c4a5c0dc8e3b1f to your computer and use it in GitHub Desktop.
Save gakuzzzz/f3df2c8073410fb5e8c4a5c0dc8e3b1f to your computer and use it in GitHub Desktop.
FutureEitherTxBoundary.scala
object Sample {
implicit def futureEitherTxBoundary[A, B](implicit ec: ExecutionContext): TxBoundary[Future[Either[A, B]]] = new TxBoundary[Future[Either[A, B]]] {
def finishTx(result: Future[Either[A, B]], tx: Tx): Future[Either[A, B]] = {
onFinishTx(result) {
case Success(Right(_)) => tx.commit()
case Success(Left(_)) => tx.rollback()
case Failure(_) => tx.rollback()
}
}
override def closeConnection(result: Future[Either[A, B]], doClose: () => Unit): Future[Either[A, B]] =
onFinishTx(result)(_ => doClose())
}
// copy from ScalikeJDBC since these are private.
/**
* Applies an operation to finish current transaction to the result.
* When the operation throws some exception, the exception will be returned without fail.
*/
private def doFinishTx[A](result: Try[A])(doFinish: Try[A] => Unit): Try[A] =
scala.util.Try(doFinish(result)).transform(
_ => result,
finishError =>
Failure(result match {
case Success(_) => finishError
case Failure(resultError) =>
resultError.addSuppressed(finishError)
resultError
}))
/**
* Applies an operation to finish current transaction to the Future value which holds the result.
* When the operation throws some exception, the exception will be returned without fail.
*/
private def onFinishTx[A](resultF: Future[A])(doFinish: Try[A] => Unit)(implicit ec: ExecutionContext): Future[A] = {
val p = Promise[A]
resultF.onComplete(result => p.complete(doFinishTx(result)(doFinish)))
p.future
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment