Consider the scenario
trait Checker {
def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]]
}
This trait is implemented by various class's.
Lets say
class CheckerImpl1 extends Checker {
override def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]] = ???
}
class CheckerImpl2 extends Checker {
override def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]] = ???
}
Now, I need to define a new function that will call check() function for each of these implementation classes in sequence(sequence does not matter) and return a new either i.e. Future[Either[String, Unit]] where String here is concatenated string of left for the check() implementation result.
So if CheckerImpl1.check() returns Left("error1") and CheckerImpl2.check() returns Left("error2") then result of the new function will return Left("error1&error2") (& just separate two strings).
OR
So if CheckerImpl1.check() returns Right(()) and CheckerImpl2.check() returns Left("error2") then result of the new function will return Left("error2").
OR
So if CheckerImpl1.check() returns Right(()) and CheckerImpl2.check() returns Right(()) then result of the new function will return Right(()).
What I have done right now is
(CheckerImpl1.check(), CheckerImpl2.check())
.mapN {
case (Right(_), Right(_)) => Right(())
case (Left(err), Right(_)) => Left(err)
case (Right(_), Left(err)) => Left(err)
case (Left(err1), Left(err2)) => Left(err1 ++ "&" ++ err2)))
}
But this is not a ideal solution, because if I add more implementation, then I would need to add more of these case statement.
Is there a better way of doing this ?