forked from politrons/reactiveScala
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEitherTMonadTransformer.scala
92 lines (76 loc) · 2.78 KB
/
EitherTMonadTransformer.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import java.util.concurrent.TimeUnit
import org.junit.Test
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.util.Try
import scalaz.std.scalaFuture._
import scalaz.{EitherT, \/}
/**
* Created by pabloperezgarcia on 15/10/2017.
*
* EitherT is a monad transformer that allow you to nest in the Combination of monad Future[\/[Left,Right]]
* Using for comprehension or just using flatMap in the pipeline we can receive the right value of the either
* and dont have to worry of the side effects of the right/left
*/
class EitherTMonadTransformer {
case class Error(msg: String)
case class User(username: String, email: String)
def authenticate(token: String): Future[Error \/ String] =
Future {
if (token == "good") {
\/.right[Error, String]("paul")
} else if (token == "partial") {
\/.right[Error, String]("unknown")
} else {
\/.left[Error, String](Error("wrong"))
}
}
def getUser(username: String): Future[Error \/ User] =
Future {
if (username == "paul") {
\/.right[Error, User](User("paul", "[email protected]"))
} else {
\/.left[Error, User](Error("Wrong username"))
}
}
def putNameInUpperCase(name: String, f: String => String): Future[Error \/ String] =
Future {
val result = Try(f.apply(name))
if (result.isSuccess) {
\/.right[Error, String](result.get)
} else {
\/.left[Error, String](Error(result.failed.get.toString))
}
}
def getEmailById(id: String): Future[\/[Error, String]] =
(for {
username <- EitherT(authenticate(id))
user <- EitherT(getUser(username))
} yield user.email).run
def getNameAndPutInUppercase(username: String): Future[\/[Error, String]] =
(for {
usernameInUpperCase <- EitherT(putNameInUpperCase(username, username => username.toUpperCase()))
} yield usernameInUpperCase).run
@Test
def eitherT(): Unit = {
val result = Await.result(getEmailById("good"), Duration.create(10, TimeUnit.SECONDS))
//All good
println(result)
val result1 = Await.result(getEmailById("bad"), Duration.create(10, TimeUnit.SECONDS))
//side effect in first future
println(result1)
val result2 = Await.result(getEmailById("partial"), Duration.create(10, TimeUnit.SECONDS))
//side effect in the second future
println(result2)
}
@Test
def eitherTWithFunction(): Unit = {
val result = Await.result(getNameAndPutInUppercase("Paul"), Duration.create(10, TimeUnit.SECONDS))
//All good
println(result)
val result1 = Await.result(getNameAndPutInUppercase(null), Duration.create(10, TimeUnit.SECONDS))
//side effect in toUppercase method
println(result1)
}
}