/
Donatron.scala
102 lines (86 loc) · 3.29 KB
/
Donatron.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
93
94
95
96
97
98
99
100
101
102
package donatron
import cats.data.EitherT
import cats.effect.IO
import cats.implicits._
import donatron.models._
import scala.util.Try
class Donatron() {
def donate(req: Request): IO[Response] =
checkForValidIntsET(req)
.flatMap(checkForMinimumDonationAmountET)
.flatMap(submitDonationsET)
.flatMap(logAndReturnAcceptedDonationsET)
.merge
.flatMap(logAndReturnResponse)
def checkForValidIntsET(req: Request): EitherT[IO, RawData, ValidDonationsFound] = {
val parts =
req.values.partition(value => Try(value.toInt).isSuccess)
EitherT.fromEither(
parts match {
case (noValidInts: List[String], allNonInts: List[String])
if noValidInts.isEmpty =>
Left(NoValidInts(invalidInts = allNonInts))
case (validDonations: List[String], nonInts: List[String]) =>
Right(ValidDonationsFound(invalidInts = nonInts, validInts = validDonations))
}
)
}
def checkForMinimumDonationAmountET(data: ValidDonationsFound): EitherT[IO, RawData, DonationsAboveMinimumFound] = {
// We want to keep using the donations as string.
// Hence, we can check that values are >= 10
// by testing that length of value is > 1
// ie., "9".length == 1, "10".length == > 2
val parts = data.validInts.partition(_.length > 1)
EitherT.fromEither(
parts match {
case (noneAboveMinimum: List[String], allBelowMinimum: List[String])
if noneAboveMinimum.isEmpty =>
Left(
NoValuesAboveMinimum(
invalidInts = data.invalidInts,
lessThanMinimum = allBelowMinimum
)
)
case (aboveMinimum: List[String], belowMinimum: List[String]) =>
Right(
DonationsAboveMinimumFound(
invalidInts = data.invalidInts,
lessThanMinimum = belowMinimum,
aboveMinimum = aboveMinimum
)
)
}
)
}
def submitDonations(data: DonationsAboveMinimumFound): IO[AcceptedDonations] =
checkForAboveMaxDonationAmount(data.aboveMinimum)
.map { validDonations =>
AcceptedDonations(
donations = validDonations,
invalidInts = data.invalidInts,
lessThanMinimum = data.lessThanMinimum
)
}
def submitDonationsET(data: DonationsAboveMinimumFound): EitherT[IO, RawData, AcceptedDonations] =
EitherT.liftF(submitDonations(data))
def checkForAboveMaxDonationAmount(data: List[String]): IO[List[String]] =
data.traverse { value =>
value.length >= 5 match {
case false => IO.pure(s"Valid Number: $value")
case true =>
IO.raiseError(
new RuntimeException("Failed to submit donations!")
)
}
}
def logAndReturnResponse(data: RawData): IO[Response] =
logResponse(data) >> IO.delay(data.toResponse)
def logResponse(data: RawData): IO[Unit] =
IO.delay(println(s"Response: ${data.toLogMessage}"))
def logAndReturnAcceptedDonations(donations: AcceptedDonations): IO[AcceptedDonations] =
IO
.delay(println(s"Valid Donations: ${donations.toLogMessage}"))
.map(_ => donations)
def logAndReturnAcceptedDonationsET(donations: AcceptedDonations): EitherT[IO, RawData, AcceptedDonations] =
EitherT.liftF(logAndReturnAcceptedDonations(donations))
}