Skip to content

Instantly share code, notes, and snippets.

@PavelZaytsev
Created December 2, 2018 04:52
Show Gist options
  • Save PavelZaytsev/8bc0b759aaff18d1dcd25535ae7003e2 to your computer and use it in GitHub Desktop.
Save PavelZaytsev/8bc0b759aaff18d1dcd25535ae7003e2 to your computer and use it in GitHub Desktop.
import scalaz.zio.{App, IO, KleisliIO}
case class AppConfig(service1QueueSize: Int,
service1SecretPath: String,
service2SecretPath: String,
service1DBToUse: String,
service2DBToUse: String,
service2MonitoringEndpoint: String)
case class SecretDependencyService(secretPath: String)
case class DBAdapter(db: String)
case class Monitor(endpoint: String)
case class Service1(queueSize: Int,
caller: SecretDependencyService,
db: DBAdapter)
case class Service2(caller: SecretDependencyService,
db: DBAdapter,
monitor: Monitor)
case class Application(service1: Service1, service2: Service2) {
def doThings(): IO[Nothing, Unit] = ???
}
object ConfigApp {
// read from file or something
val fromConfigPathToConfig: String => AppConfig = ???
val fromConfigPathToConfigK =
KleisliIO.lift(fromConfigPathToConfig)
val fromConfigToQueueSizeK =
KleisliIO.lift { config: AppConfig =>
config.service1QueueSize
}
val fromConfigToSecretPath1K = KleisliIO.lift { config: AppConfig =>
config.service1SecretPath
}
val fromConfigToSecretPath2K = KleisliIO.lift { config: AppConfig =>
config.service2SecretPath
}
val fromSecretPathToSecretDependencyServiceK = KleisliIO.lift {
path: String =>
SecretDependencyService(path)
}
val fromConfigToDB1K = KleisliIO.lift { config: AppConfig =>
config.service1DBToUse
}
val fromConfigToDB2K = KleisliIO.lift { config: AppConfig =>
config.service2DBToUse
}
val fromDBtoDBAdapterK = KleisliIO.lift { db: String =>
DBAdapter(db)
}
val fromConfigToMonitorEndpointK = KleisliIO.lift { config: AppConfig =>
config.service2MonitoringEndpoint
}
val fromMonitorEndpointToMonitorK = KleisliIO.lift { monitor: String =>
Monitor(monitor)
}
// fuse 'em up
val fromPathToService1K: String => KleisliIO[Nothing, String, Service1] = {
path: String =>
val queueSizeK
: KleisliIO[Nothing, String, Int] = fromConfigPathToConfigK >>> fromConfigToQueueSizeK
val secretService1K
: KleisliIO[Nothing, String, SecretDependencyService] = fromConfigPathToConfigK >>> fromConfigToSecretPath1K >>> fromSecretPathToSecretDependencyServiceK
val dbAdapter1K
: KleisliIO[Nothing, String, DBAdapter] = fromConfigPathToConfigK >>> fromConfigToDB1K >>> fromDBtoDBAdapterK
// Kleisli is a monad itself lol
for {
((queueSize, secretService1), dbAdapter) <- queueSizeK &&& secretService1K &&& dbAdapter1K
} yield Service1(queueSize, secretService1, dbAdapter)
}
val fromPathToService2K: String => KleisliIO[Nothing, String, Service2] = {
path: String =>
val secretService2K
: KleisliIO[Nothing, String, SecretDependencyService] = fromConfigPathToConfigK >>> fromConfigToSecretPath2K >>> fromSecretPathToSecretDependencyServiceK
val dbAdapterK
: KleisliIO[Nothing, String, DBAdapter] = fromConfigPathToConfigK >>> fromConfigToDB2K >>> fromDBtoDBAdapterK
val monitorK
: KleisliIO[Nothing, String, Monitor] = fromConfigPathToConfigK >>> fromConfigToMonitorEndpointK >>> fromMonitorEndpointToMonitorK
for {
((secretService2, dbAdapter), monitor) <- secretService2K &&& dbAdapterK &&& monitorK
} yield Service2(secretService2, dbAdapter, monitor)
}
val fromPathToApp: String => KleisliIO[Nothing, String, Application] = {
path: String =>
for {
(service1, service2) <- fromPathToService1K(path) &&& fromPathToService2K(
path)
} yield Application(service1, service2)
}
def buildAppFromConfig(configPath: String): IO[Nothing, Application] =
fromPathToApp(configPath).run(configPath)
}
object KleisliConfig extends App {
def run(args: List[String]): IO[Nothing, ExitStatus] =
program.attempt.map(_.fold(_ => 1, _ => 0)).map(ExitStatus.ExitNow(_))
def program: IO[Nothing, Unit] =
for {
appInstance <- ConfigApp.buildAppFromConfig("productionConfig.json")
_ <- appInstance.doThings()
} yield ()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment