Skip to content

Instantly share code, notes, and snippets.

@makiftutuncu
Created July 16, 2022 07:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save makiftutuncu/da7866d2b43dbb217c69ac4ffbd0354c to your computer and use it in GitHub Desktop.
Save makiftutuncu/da7866d2b43dbb217c69ac4ffbd0354c to your computer and use it in GitHub Desktop.
Sharing Builder Code by Some Scala Tricks
case class BarDBConfig(connectionString: String) extends DBConfig
object BarDBConfig extends DBConfig.Builder[BarDBConfig]("bar")
trait DBConfig(val connectionString: String)
object DBConfig {
// 1. `Builder` extends `Function` type `String => C`
abstract class Builder[C <: DBConfig](val prefix: String) extends (String => C) {
// Some generic build logic
def build(map: Map[String, String]): Option[C] =
map.get(prefix) match {
case Some(connectionString) =>
// Calling `apply` because it exists due to `Builder` extending `Function` type
Some(apply(connectionString))
case None => None
}
}
}
// 2. This is a case class so it generates an `apply` method conforming to `String => FooDBConfig` type.
case class FooDBConfig(connectionString: String) extends DBConfig
// 3. Generated `apply` happens to match the `apply` method defined in `Function` type `Builder` extends.
// That's why the `apply` that `Function` defines is implemented by the `apply` that case class generates.
object FooDBConfig extends DBConfig.Builder[FooDBConfig]("foo")
val dbConfigMap: Map[String, String] = Map(
"foo" -> "fooConnectionString",
"bar" -> "barConnectionString"
)
// 4. Since correct implementation of `apply` is provided by case class, this works!
val fooDBConfig: Option[FooDBConfig] = FooDBConfig.build(dbConfigMap)
val barDBConfig: Option[BarDBConfig] = BarDBConfig.build(dbConfigMap)
fooDBConfig.isDefined // true
barDBConfig.isDefined // true
val printConfigs: ZIO[FooDBConfig & BarDBConfig, Nothing, Unit] =
for {
fooDBConfig <- ZIO.environment[FooDBConfig]
barDBConfig <- ZIO.environment[BarDBConfig]
} yield {
println(fooDBConfig)
println(barDBConfig)
}
// 5. This makes it easy to work in some `ZIO` environment that needs both DB configurations
// because they are different types but built the same way easily!
printConfigs.provide(fooDBConfig.get, barDBConfig.get)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment