Skip to content

Instantly share code, notes, and snippets.

@poslegm
Created October 17, 2021 21:20
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 poslegm/f252994a15453457e64d6498249928f3 to your computer and use it in GitHub Desktop.
Save poslegm/f252994a15453457e64d6498249928f3 to your computer and use it in GitHub Desktop.
Scala programmer discovers DI
import izumi.reflect.Tag
import shapeless.tag
import shapeless.tag._
import zio._
import zio.magic._
import scala.language.implicitConversions
import BillingClient._
import NotificatorClient._
object Main extends CustomApp {
type Env = BillingClient with NotificatorClient
val layers = ZLayer.fromMagic[Env](
Grpc.live,
// tag layer by target service
GrpcConfig.load("billing").tagged[BillingClient.Service],
GrpcConfig.load("notificator").tagged[NotificatorClient.Service],
// replace type to tagged one in the ZLayer's input
BillingClientLive.live.requireTagged[GrpcConfig, BillingClient.Service, Has[Grpc]],
NotificatorClientLive.live.requireTagged[GrpcConfig, NotificatorClient.Service, Has[Grpc]]
)
}
// ZLAYER SYNTAX ===============
class ZLayerExtensionsRequireTagged[RIn, E, ROut](
private val layer: ZLayer[RIn, E, ROut]
) {
def requireTagged[A: Tag, T: Tag, RIn1: Tag](implicit
ev: RIn1 with Has[A] =:= RIn,
union: Has.Union[RIn1, Has[A]]
): ZLayer[Has[A @@ T] with RIn1, E, ROut] =
ZLayer.environment[Has[A @@ T]].flatMap { tagged =>
(ZLayer.environment[RIn1] ++ ZLayer.succeed(untag(tagged.get))).map(ev) >>>
layer
}
}
class ZLayerExtensionsTagged[-RIn, +E, ROut](
private val layer: ZLayer[RIn, E, Has[ROut]]
) extends AnyVal {
def tagged[LayerTag: Tag](implicit
ROut: Tag[ROut]
): ZLayer[RIn, E, Has[ROut @@ LayerTag]] =
layer.map(out => Has(tag[LayerTag](out.get)))
}
trait ZLayerSyntax {
implicit def zLayerSyntax[RIn, E, ROut: Tag](
layer: ZLayer[RIn, E, Has[ROut]]
): ZLayerExtensionsTagged[RIn, E, ROut] =
new ZLayerExtensionsTagged(layer)
implicit def zLayerSyntax1[RIn, E, ROut](
layer: ZLayer[RIn, E, ROut]
): ZLayerExtensionsRequireTagged[RIn, E, ROut] =
new ZLayerExtensionsRequireTagged(layer)
}
trait CustomApp extends ZLayerSyntax
// MODULES DEFENITIONS ==========
case class GrpcConfig(name: String)
object GrpcConfig {
def load(name: String) = ZLayer.succeed(GrpcConfig(name))
}
case class Grpc()
object Grpc {
val live = ZLayer.succeed(Grpc())
}
object BillingClient {
type BillingClient = Has[Service]
trait Service {}
}
case class BillingClientLive(config: GrpcConfig, grpc: Grpc) extends BillingClient.Service
object BillingClientLive {
val live: URLayer[Has[GrpcConfig] with Has[Grpc], BillingClient] =
(BillingClientLive(_, _)).toLayer
}
object NotificatorClient {
type NotificatorClient = Has[Service]
trait Service {}
}
case class NotificatorClientLive(config: GrpcConfig, grpc: Grpc) extends NotificatorClient.Service
object NotificatorClientLive {
val live: URLayer[Has[GrpcConfig] with Has[Grpc], NotificatorClient] =
(NotificatorClientLive(_, _)).toLayer
}
// UTILS =======================
def untag[A, B](x: A @@ B): A = x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment