-
Notifications
You must be signed in to change notification settings - Fork 0
/
readerT.sc
96 lines (81 loc) · 2.95 KB
/
readerT.sc
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
import cats.data.ReaderT
import cats.{Applicative, Monad}
import cats.effect.{ExitCode, IO, IOApp}
import fs2.Stream
import cats.syntax.apply._
import cats.syntax.functor._
case class Config(fooConfig: Config.FooConfig, barConfig: Config.BarConfig, bazConfig: Config.BazConfig)
object Config {
trait FooConfig
trait BarConfig
trait BazConfig
}
case class Clients[F[_]](fooClient: Clients.FooClient[F], barClient: Clients.BarClient[F], bazClient: Clients.BazClient[F])
object Clients {
def readerT[F[_] : Applicative]: ReaderT[F, Config, Clients[F]] = (
FooClient.readerT[F],
BarClient.readerT[F],
BazClient.readerT[F]
).mapN(Clients.apply)
trait BarClient[F[_]]
object BarClient {
def readerT[F[_]]: ReaderT[F, Config, BarClient[F]] = readerT_.local(_.barConfig)
private def readerT_[F[_]]: ReaderT[F, Config.BarConfig, BarClient[F]] = ???
}
trait BazClient[F[_]]
object BazClient {
def readerT[F[_]]: ReaderT[F, Config, BazClient[F]] = readerT_.local(_.bazConfig)
private def readerT_[F[_]]: ReaderT[F, Config.BazConfig, BazClient[F]] = ???
}
trait FooClient[F[_]]
object FooClient {
def readerT[F[_]]: ReaderT[F, Config, FooClient[F]] = readerT_.local(_.fooConfig)
private def readerT_[F[_]]: ReaderT[F, Config.FooConfig, FooClient[F]] = ???
}
}
case class Handlers[F[_]](quxHandler: Handlers.QuxHandler[F], quuxHandler: Handlers.QuuxHandler[F])
object Handlers {
def readerT[F[_]: Monad]: ReaderT[F, Config, Handlers[F]] = Clients.readerT.andThen(
(
QuxHandler.readerT[F],
QuuxHandler.readerT[F]
).mapN(Handlers.apply)
)
trait QuxHandler[F[_]]
object QuxHandler {
def readerT[F[_]]: ReaderT[F, Clients[F], QuxHandler[F]] = readerT_.local(
clients => (clients.fooClient, clients.barClient)
)
private def readerT_[F[_]]: ReaderT[F, (Clients.FooClient[F], Clients.BarClient[F]), QuxHandler[F]] = ???
}
trait QuuxHandler[F[_]]
object QuuxHandler {
def readerT[F[_]]: ReaderT[F, Clients[F], QuuxHandler[F]] = readerT_.local(
clients => (clients.barClient, clients.bazClient)
)
private def readerT_[F[_]]: ReaderT[F, (Clients.BarClient[F], Clients.BazClient[F]), QuuxHandler[F]] = ???
}
}
case class Streams[F[_]](streamA: Stream[F, Unit], streamB: Stream[F, Unit])
object Streams {
object StreamA {
def readerT[F[_]]: ReaderT[F, Handlers[F], Stream[F, Unit]] = ???
}
object StreamB {
def readerT[F[_]]: ReaderT[F, Handlers[F], Stream[F, Unit]] = ???
}
def readerT[F[_]: Monad]: ReaderT[F, Config, Streams[F]] = Handlers.readerT[F].andThen(
(
StreamA.readerT[F],
StreamB.readerT[F]
).mapN(Streams.apply)
)
}
object ServiceApp extends IOApp {
val config: Config = ???
def stream: Stream[IO, Unit] = for {
streams <- Stream.eval(Streams.readerT[IO].run(config))
_ <- streams.streamA.merge(streams.streamB)
} yield ()
override def run(args: List[String]): IO[ExitCode] = stream.compile.drain.as(ExitCode.Success)
}