Skip to content

Instantly share code, notes, and snippets.

@ayoub-benali
Forked from atamborrino/ErrorFailure.scala
Created April 5, 2016 14:45
Show Gist options
  • Save ayoub-benali/0490b1e682315d54e530e81f1516b55c to your computer and use it in GitHub Desktop.
Save ayoub-benali/0490b1e682315d54e530e81f1516b55c to your computer and use it in GitHub Desktop.
Monad transformer for Future[A Or Every[Error]]
package models.error
import org.scalactic._
import scala.concurrent.{ExecutionContext, Future}
import org.scalactic.Accumulation._
trait Error
object FutureOr {
type Errors = Every[Error]
object Implicits {
implicit class FutureOps[A](val futAOrError: Future[A Or Errors]) extends AnyVal {
def wrap: FutureOr[A] = new FutureOr(futAOrError)
}
}
import Implicits._
class FutureOr[A](val futAOrError: Future[A Or Errors]) extends AnyVal {
def flatMap[B](f: A => FutureOr[B])(implicit ec: ExecutionContext): FutureOr[B] = {
new FutureOr(
futAOrError.flatMap {
case Good(a) => f(a).unwrap
case Bad(err) => Future.successful(Bad(err))
}
)
}
def map[B](f: A => B)(implicit ec: ExecutionContext): FutureOr[B] =
flatMap(a => new FutureOr(Future.successful(Good(f(a)))))
def mapWithMaybeError[B](f: A => B Or Errors)(implicit ec: ExecutionContext): FutureOr[B] =
flatMap(a => new FutureOr(Future.successful(f(a))))
def zip[B](futBOrError: FutureOr[B])(implicit ec: ExecutionContext): FutureOr[(A, B)] = {
new FutureOr(
(futAOrError zip futBOrError.unwrap).map { case (aOrError, bOrError) => aOrError zip bOrError }
)
}
def unwrap: Future[A Or Errors] = futAOrError
}
def traverse[A, B](as: Seq[A])(f: A => FutureOr[B])(implicit ec: ExecutionContext): FutureOr[Seq[B]] = {
new FutureOr(Future.traverse(as)(a => f(a).unwrap).map(_.combined))
}
def sequence[A](futAsOrError: Seq[FutureOr[A]])(implicit ec: ExecutionContext): FutureOr[Seq[A]] = {
new FutureOr(Future.sequence(futAsOrError.map(_.unwrap)).map(_.combined))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment