Last active
October 18, 2018 08:16
-
-
Save Tvaroh/3e40d8866c3e7f6dacb9c34f7f393c9d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.UUID | |
import cats.data.EitherT | |
import cats.effect.IO | |
import cats.implicits._ | |
import cats.{Applicative, ApplicativeError} | |
import io.circe.syntax._ | |
import io.circe.{Encoder, Json} | |
object example extends App { | |
// typeclasses | |
trait Raise[F[_], E] { | |
def raise[A](err: E): F[A] | |
} | |
object Raise { | |
implicit def raiseApplicativeError[F[_], E, E1](implicit appErr: ApplicativeError[F, E], | |
adapt: Adapt[E1, E]): Raise[F, E1] = | |
new Raise[F, E1] { | |
override def raise[A](err: E1): F[A] = appErr.raiseError(adapt.adapt(err)) | |
} | |
} | |
trait Adapt[E, E1] { | |
def adapt(e: E): E1 | |
} | |
object Adapt { | |
implicit def adaptSubtyping[E, E1](implicit sub: E1 <:< E): Adapt[E1, E] = | |
(e: E1) => sub(e) | |
} | |
// global state | |
var analyses: Set[UUID] = Set.empty | |
// interfaces | |
trait RunAnalysis[F[_]] { | |
def runAnalysis(value: Int): F[UUID] | |
} | |
trait CancelAnalysis[F[_]] { | |
def cancelAnalysis(id: UUID): F[Unit] | |
} | |
// implementations | |
sealed trait RunAnalysisError { | |
def errorCode: String | |
} | |
object RunAnalysisError { | |
object NegativeValue extends RunAnalysisError { | |
override def errorCode: String = "NEGATIVE_VALUE" | |
} | |
implicit val encoder: Encoder[RunAnalysisError] = | |
(err: RunAnalysisError) => Json.obj("errorCode" -> Json.fromString(err.errorCode)) | |
} | |
class RunAnalysisImpl[F[_]: Applicative](implicit raise: Raise[F, RunAnalysisError]) | |
extends RunAnalysis[F] { | |
override def runAnalysis(value: Int): F[UUID] = | |
if (value >= 0) { | |
val analysisUuid = UUID.randomUUID() | |
analyses = analyses + analysisUuid | |
analysisUuid.pure[F] | |
} else { | |
raise.raise(RunAnalysisError.NegativeValue: RunAnalysisError) | |
} | |
} | |
sealed trait CancelAnalysisError { | |
def errorCode: String | |
} | |
object CancelAnalysisError { | |
object AnalysisNotFound extends CancelAnalysisError { | |
override def errorCode: String = "ANALYSIS_NOT_FOUND" | |
} | |
implicit val encoder: Encoder[CancelAnalysisError] = | |
(err: CancelAnalysisError) => Json.obj("errorCode" -> Json.fromString(err.errorCode)) | |
} | |
class CancelAnalysisImpl[F[_]: Applicative](implicit raise: Raise[F, CancelAnalysisError]) | |
extends CancelAnalysis[F] { | |
override def cancelAnalysis(id: UUID): F[Unit] = | |
if (analyses(id)) { | |
analyses = analyses - analysisUuid | |
().pure[F] | |
} | |
else raise.raise(CancelAnalysisError.AnalysisNotFound: CancelAnalysisError) | |
} | |
// wiring | |
object wiring { | |
type F[T, E] = EitherT[IO, E, T] | |
implicit def raiseAdapt[E: Encoder]: Adapt[E, Json] = (e: E) => e.asJson | |
val runAnalysis: RunAnalysis[F[?, Json]] = | |
new RunAnalysisImpl | |
val cancelAnalysis: CancelAnalysis[F[?, Json]] = | |
new CancelAnalysisImpl | |
} | |
// apps | |
import wiring._ | |
println(runAnalysis.runAnalysis(-1).value.unsafeRunSync()) | |
// Left({ | |
// "errorCode" : "NEGATIVE_VALUE" | |
//}) | |
println(cancelAnalysis.cancelAnalysis(UUID.randomUUID()).value.unsafeRunSync()) | |
// Left({ | |
// "errorCode" : "ANALYSIS_NOT_FOUND" | |
//}) | |
println { | |
(for { | |
id <- runAnalysis.runAnalysis(1) | |
_ <- cancelAnalysis.cancelAnalysis(id) | |
} yield id).value.unsafeRunSync() | |
} | |
// Right(uuid) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment