Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save iamanandkris/87deef653ba51582a7de2a06d19fc1af to your computer and use it in GitHub Desktop.
Save iamanandkris/87deef653ba51582a7de2a06d19fc1af to your computer and use it in GitHub Desktop.
import zio.{Has, Layer, Ref, Task, ZIO, ZLayer}
import zio._
import zio.console._
object ZIOInsteadOfFreeRewrite extends App {
type UserID = String
case class UserProfile(name: String)
//Base trait for all the operations that are to be recorded when running test
trait Operation
//The TestState
final case class ExecutedInstructions(ops: List[Operation])
type DatabaseService = Has[Database.Service]
type LoggerService = Has[Logger.Service]
object Database {
//Service
trait Service {
def lookup(id: UserID): Task[UserProfile]
def update(id: UserID, profile: UserProfile): Task[Unit]
}
def testService(ref: Ref[ExecutedInstructions]): Layer[Nothing, DatabaseService] = ZLayer.succeed(DatabaseTestService(ref))
//def live(ref: Ref[ExecutedInstructions]): Layer[Nothing, DatabaseService] = ZLayer.succeed(DatabaseTestService(ref))
}
object Logger {
trait Service {
def info(id: String): Task[Unit]
}
def testService(ref: Ref[ExecutedInstructions]): Layer[Nothing, LoggerService] = ZLayer.succeed(LoggerTestService(ref))
//def live(ref: Ref[ExecutedInstructions]): Layer[Nothing, LoggerService] = ZLayer.succeed(LoggerTestService(ref))
}
// A concurrent-safe test logger service, which uses a `Ref` to keep track
// of changes to the instruction set:
case class LoggerTestService(ref: Ref[ExecutedInstructions]) extends Logger.Service {
def info(line: String): Task[Unit] =
ref.update(x => x.copy(ops = x.ops :+ LoggerTestService.MessageLogged(line))).map(x => ())
}
object LoggerTestService {
trait LoggerOperation extends Operation
case class MessageLogged(message: String) extends LoggerOperation
}
//Test Service Implementation
case class DatabaseTestService(ref: Ref[ExecutedInstructions]) extends Database.Service{
private var map: Map[UserID, UserProfile] = Map("abc" -> UserProfile("testName"))
def lookup(id: UserID): Task[UserProfile] =
ref.update(x => x.copy(ops = x.ops :+ DatabaseTestService.UserLookedUp(id))).map(x => map(id))
def update(id: UserID, profile: UserProfile): Task[Unit] =
ref.update(x => x.copy(ops = x.ops :+ DatabaseTestService.UserUpdated(id, profile))).map(x => map = map + (id -> profile))
}
object DatabaseTestService {
// database operations performed against the database:
trait DatabaseOperation extends Operation
case class UserUpdated(id: UserID, profile: UserProfile) extends DatabaseOperation
case class UserLookedUp(id: UserID) extends DatabaseOperation
}
val function = for {
profile <- database.lookup("abc")
_ <- logger.info(profile.name)
} yield profile
override def run(args: List[String]): ZIO[zio.ZEnv, Nothing, ExitCode] = {
(for {
instructionRef <- Ref.make(ExecutedInstructions(Nil))
res <- function.provideCustomLayer(Database.testService(instructionRef) ++ Logger.testService(instructionRef))
_ <- putStrLn(res.toString)
}yield res).map(x => ExitCode.success).orDie
}
}
import ZIOInsteadOfFreeRewrite._
package object database {
def lookup(id: UserID) = ZIO.accessM[DatabaseService](_.get.lookup(id))
def update(id: UserID, profile: UserProfile) =
ZIO.accessM[DatabaseService](_.get.update(id, profile))
}
package object logger {
def info(message: String) = ZIO.accessM[LoggerService](_.get.info(message))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment