Skip to content

Instantly share code, notes, and snippets.

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 dacr/f293a05776307e94a2084b3c3915d796 to your computer and use it in GitHub Desktop.
Save dacr/f293a05776307e94a2084b3c3915d796 to your computer and use it in GitHub Desktop.
ZIO learning - structured services - vertical composition / published by https://github.com/dacr/code-examples-manager #73bc55eb-d065-4fcc-81c0-db0ead534f96/1a444fff9bb6c9946585502c318af4341b3ac33
// summary : ZIO learning - structured services - vertical composition
// keywords : scala, zio, learning, services, pure-functional, @testable
// publish : gist
// authors : Rock the JVM
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : 73bc55eb-d065-4fcc-81c0-db0ead534f96
// created-on : 2021-05-03T18:43:49+02:00
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// Highly inspired from Structuring Services in Scala with ZIO and ZLayer : https://www.youtube.com/watch?v=PaogLRrYo64
// And lately updated or Scala3 & ZIO2
// ---------------------
//> using scala "3.2.2"
//> using dep "dev.zio::zio:2.0.13"
// ---------------------
import zio.*
// ----------------------------------------------------------------------------------------
case class User(name: String, email: String)
// ----------------------------------------------------------------------------------------
// This is the classical service pattern used within ZIO, with the standard naming scheme
// Service definition
trait UserEmailer:
def notify(user: User, message: String): Task[Unit]
object UserEmailer:
class UserEmailerImpl() extends UserEmailer:
override def notify(user: User, message: String): Task[Unit] =
ZIO.attempt(println(s"[User emailer] Sending '$message' to ${user.email}'"))
val live: URLayer[Any, UserEmailer] = ZLayer.succeed(UserEmailerImpl())
// Front-facing API - helper function
def notify(user: User, message: String): RIO[UserEmailer, Unit] =
ZIO.serviceWithZIO(_.notify(user, message))
// ----------------------------------------------------------------------------------------
trait UserDb:
def insert(user: User): Task[Unit]
object UserDb:
class UserDbImpl extends UserDb:
override def insert(user: User) = ZIO.attempt(
println(s"[Database] insert into public.user value ('${user.email}')")
)
val live = ZLayer.succeed(UserDbImpl())
def insert(user: User): RIO[UserDb, Unit] =
ZIO.serviceWithZIO(_.insert(user))
// ----------------------------------------------------------------------------------------
class UserSubscription(notifier: UserEmailer, userDb: UserDb):
def subscribe(user: User): Task[User] =
for
_ <- userDb.insert(user)
_ <- notifier.notify(user, s"Welcome to this site, ${user.email}")
yield user
object UserSubscription:
val live: URLayer[UserEmailer & UserDb, UserSubscription] = ZLayer(
for
userEmailer <- ZIO.service[UserEmailer]
userDb <- ZIO.service[UserDb]
yield UserSubscription(userEmailer, userDb)
)
// front-facing API
def subscribe(user: User): RIO[UserSubscription, User] =
ZIO.serviceWithZIO(_.subscribe(user))
// ----------------------------------------------------------------------------------------
object Encapsulated extends ZIOAppDefault:
val david = User("david", "myemail@gmail.com")
val layers = ZLayer.make[UserDb & UserEmailer & UserSubscription](
UserDb.live,
UserEmailer.live,
UserSubscription.live
)
val logic =
UserSubscription
.subscribe(david)
.provideLayer(layers)
override def run = logic
Encapsulated.main(Array.empty)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment