Skip to content

Instantly share code, notes, and snippets.

@fanf
Created March 17, 2019 09:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fanf/dee9696af98a22c7fae659e12892989f to your computer and use it in GitHub Desktop.
Save fanf/dee9696af98a22c7fae659e12892989f to your computer and use it in GitHub Desktop.
/*
* My application is splitted in several modules, possibly independently built and
* distributed.
* I have a Base error trait for the whole application.
*
* Each module has its own business error defined by a module base error trait which
* extends BaseError.
*
* I want to have a common framework to manage bridging errors between modules so
* that a module can use the other ones and subsume error type to its own, especially
* in the canonical exemple:
*
* ```
* for {
* a <- module1
* b <- module2
* } yield {
* ...
* } : error of kind module 3
* ```
*
* The bridging could be done with a "chain" error kind that encapsulated one error module
* in an other: `ErrorModule2.Chain("some explanation", errorModule1)`
*
* Finally, I want minimum boilerplate for that. How is it usually done?
*/
object errors {
trait BaseError {
def msg: String
}
trait BaseChainError[E <: BaseError] extends BaseError {
def cause: E
def hint: String
def msg = s"${hint}; cause was: ${cause.getClass.getSimpleName}: ${cause.msg}"
}
}
object TestImplicits {
import scalaz.zio._
import scalaz.zio.syntax._
object module1 {
import com.normation.errors._
sealed trait M_1_Error extends BaseError
object M_1_Error {
final case class BusinessError1(msg: String) extends M_1_Error
final case class Chained[E <: BaseError](hint: String, cause: E) extends M_1_Error with BaseChainError[E]
}
object M_1_Result {
// implicits ?
}
object service1 {
def doStuff(param: String): IO[M_1_Error, String] = param.succeed
}
}
object module2 {
import com.normation.errors._
sealed trait M_2_Error extends BaseError
object M_2_Error {
final case class MissingImportantStuff(msg: String) extends M_2_Error
final case class Chained[E <: BaseError](hint: String, cause: E) extends M_2_Error with BaseChainError[E]
}
object M_2_Result {
// implicits
}
object service2 {
def doStuff(param: Int): IO[M_2_Error, Int] = param.succeed
}
}
object testModule {
import module1._
import module2._
import com.normation.errors._
sealed trait M_3_Error extends BaseError
object M_3_Error {
final case class Oups(msg: String) extends M_3_Error
final case class Chained[E <: BaseError](hint: String, cause: E) extends M_3_Error with BaseChainError[E]
}
object M_3_Result {
// implicits ?
}
import module1.M_1_Result._
import module2.M_2_Result._
import M_3_Result._
/*
* I would like all of that to be possible, with the minimum boilerplate,
* and the maximum homogeneity between modules
*/
object service {
// need error adpatation 1 toward 2
def test0(a: String): IO[M_2_Error, Int] = service1.doStuff(a)
// need error adpatation 1 toward 3
def test1(a: String): IO[M_3_Error, Int] = service1.doStuff(a)
// need error adpatation 1 and 2 toward 3
def test2(a: String, b: Int): IO[M_3_Error, (String, Int)] = {
for {
x <- service1.doStuff(a)
y <- service2.doStuff(b)
} yield {
(x, y)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment