Last active
May 26, 2024 18:25
-
-
Save Yummy-Yums/ed5d572ae5291a18daca577cf82b3cb4 to your computer and use it in GitHub Desktop.
ZIO Services pattern tutorial
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import zio._ | |
case class Doc( | |
title: String, | |
description: String, | |
language: String, | |
format: String, | |
content: Array[Byte] | |
) | |
trait DocRepo { | |
def get(id: String): ZIO[Any, Throwable, Doc] | |
def save(document: Doc): ZIO[Any, Throwable, String] | |
def delete(id: String): ZIO[Any, Throwable, Unit] | |
def findByTitle(title: String): ZIO[Any, Throwable, List[Doc]] | |
} | |
case class DocRepoImpl( | |
metadataRepo: MetadataRepo, | |
BlobStorage: BlobStorage | |
) extends DocRepo { | |
override def get(id: String): ZIO[Any, Throwable, Doc] = | |
for { | |
metadata <- metadataRepo.get(id) | |
content <- BlobStorage.get(id) | |
} yield Doc( | |
metadata.title, | |
metadata.description, | |
metadata.language, | |
metadata.format, | |
content | |
) | |
override def save(document: Doc): ZIO[Any, Throwable, String] = | |
for { | |
id <- BlobStorage.put(document.content) | |
_ <- metadataRepo.put( | |
id, | |
Metadata( | |
document.title, | |
document.description, | |
document.language, | |
document.format | |
) | |
) | |
} yield id | |
override def delete(id: String): ZIO[Any, Throwable, Unit] = | |
for { | |
_ <- BlobStorage.delete(id) | |
_ <- metadataRepo.delete(id) | |
} yield () | |
override def findByTitle(title: String): ZIO[Any, Throwable, List[Doc]] = | |
for { | |
map <- metadataRepo.findByTitle(title) | |
content <- ZIO.foreach(map)((id, metadata) => | |
for { | |
content <- BlobStorage.get(id) | |
} yield id -> Doc( | |
metadata.title, | |
metadata.description, | |
metadata.language, | |
metadata.format, | |
content | |
) | |
) | |
} yield content.values.toList | |
} | |
object DocRepo { | |
def get(id: String): ZIO[DocRepo, Throwable, Doc] = | |
ZIO.serviceWithZIO[DocRepo](_.get(id)) | |
def save(document: Doc): ZIO[DocRepo, Throwable, String] = | |
ZIO.serviceWithZIO[DocRepo](_.save(document)) | |
def delete(id: String): ZIO[DocRepo, Throwable, Unit] = | |
ZIO.serviceWithZIO[DocRepo](_.delete(id)) | |
def findByTitle(title: String): ZIO[DocRepo, Throwable, List[Doc]] = | |
ZIO.serviceWithZIO[DocRepo](_.findByTitle(title)) | |
} | |
case class Metadata( | |
title: String, | |
description: String, | |
language: String, | |
format: String | |
) | |
trait MetadataRepo { | |
def get(id: String): ZIO[Any, Throwable, Metadata] | |
def put(id: String, metadata: Metadata): ZIO[Any, Throwable, Unit] | |
def delete(id: String): ZIO[Any, Throwable, Unit] | |
def findByTitle(title: String): ZIO[Any, Throwable, Map[String, Metadata]] | |
} | |
case class MetadataImpl(map: Ref[Map[String, Metadata]]) extends MetadataRepo { | |
override def get(id: String): ZIO[Any, Throwable, Metadata] = { | |
println("this is the map" + map.get) | |
map.get.map(_.get(id).get) | |
} | |
override def put(id: String, metadata: Metadata): ZIO[Any,Throwable,Unit] = | |
for { | |
id <- Random.nextUUID.map(_.toString) | |
_ <- map.update(_ + (id -> metadata)) | |
} yield () | |
override def delete(id: String): ZIO[Any,Throwable,Unit] = | |
map.get.map(_.-(id)) | |
override def findByTitle(title: String): ZIO[Any,Throwable, Map[String, Metadata]] = { | |
map.get.map{ everyMap => | |
everyMap.filter{ | |
case (_, metadata) => metadata.title == title | |
} | |
} | |
} | |
} | |
object MetadataRepo { | |
def get(id: String): ZIO[MetadataRepo, Throwable, Metadata] = | |
ZIO.serviceWithZIO[MetadataRepo](_.get(id)) | |
def put(id: String, metadata: Metadata): ZIO[MetadataRepo, Throwable, Unit] = | |
ZIO.serviceWithZIO[MetadataRepo](_.put(id, metadata)) | |
def delete(id: String): ZIO[MetadataRepo, Throwable, Unit] = | |
ZIO.serviceWithZIO[MetadataRepo](_.delete(id)) | |
def findByTitle(title: String): ZIO[MetadataRepo, Throwable, Map[String, Metadata]] = | |
ZIO.serviceWithZIO[MetadataRepo](_.findByTitle(title)) | |
} | |
trait BlobStorage { | |
def get(id: String): ZIO[Any, Throwable, Array[Byte]] | |
def put(content: Array[Byte]): ZIO[Any, Throwable, String] | |
def delete(id: String): ZIO[Any, Throwable, Unit] | |
} | |
case class BlobStorageImpl(map: Ref[Map[String, Array[Byte]]]) extends BlobStorage { | |
override def get(id: String): ZIO[Any, Throwable, Array[Byte]] = | |
map.get.flatMap { storage => | |
storage.get(id) match { | |
case Some(content) => ZIO.succeed(content) | |
case None => ZIO.fail(new Exception("Blob not found")) | |
} | |
} | |
override def put(content: Array[Byte]): ZIO[Any, Throwable, String] = | |
for { | |
id <- Random.nextUUID.map(_.toString) | |
_ <- map.update(_ + (id -> content)) | |
} yield id | |
override def delete(id: String): ZIO[Any, Throwable, Unit] = | |
map.update(_ - id).unit | |
} | |
object BlobStorage { | |
def get(id: String): ZIO[BlobStorage, Throwable, Array[Byte]] = | |
ZIO.serviceWithZIO[BlobStorage](_.get(id)) | |
def put(content: Array[Byte]): ZIO[BlobStorage, Throwable, String] = | |
ZIO.serviceWithZIO[BlobStorage](_.put(content)) | |
def delete(id: String): ZIO[BlobStorage, Throwable, Unit] = | |
ZIO.serviceWithZIO[BlobStorage](_.delete(id)) | |
} | |
object InmemoryMetadataRepo { | |
val layer = | |
ZLayer.fromZIO{ | |
Ref.make(Map.empty[String, Metadata]).map(new MetadataImpl(_)) | |
} | |
} | |
object InmemoryBlobStorage { | |
val layer = | |
ZLayer.fromZIO { | |
Ref.make(Map.empty[String, Array[Byte]]).map(new BlobStorageImpl(_)) | |
} | |
} | |
object DocRepoImpl { | |
val layer: ZLayer [BlobStorage with MetadataRepo, Nothing, DocRepo] = | |
ZLayer { | |
for { | |
metadataRepo <- ZIO.service[MetadataRepo] | |
BlobStorage <- ZIO.service[BlobStorage] | |
} yield DocRepoImpl(metadataRepo, BlobStorage) | |
} | |
} | |
import zio._ | |
import java.io.IOException | |
object MainApp extends ZIOAppDefault { | |
val app = | |
for { | |
id <- | |
DocRepo.save( | |
Doc( | |
"title", | |
"description", | |
"en", | |
"text/plain", | |
"content".getBytes() | |
) | |
) | |
doc <- DocRepo.get(id) | |
_ <- Console.printLine(doc) | |
_ <- Console.printLine( | |
s""" | |
|Downloaded the document with $id id: | |
| title: ${doc.title} | |
| description: ${doc.description} | |
| language: ${doc.language} | |
| format: ${doc.format} | |
|""".stripMargin | |
) | |
_ <- DocRepo.delete(id) | |
_ <- Console.printLine(s"Deleted the document with $id id") | |
} yield () | |
def run = | |
app.provide( | |
DocRepoImpl.layer, | |
InmemoryBlobStorage.layer, | |
InmemoryMetadataRepo.layer | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment