Skip to content

Instantly share code, notes, and snippets.

@przemek-pokrywka
Last active November 14, 2021 19:51
Show Gist options
  • Save przemek-pokrywka/d86787767a1ccc9201f5855d9ebeb42f to your computer and use it in GitHub Desktop.
Save przemek-pokrywka/d86787767a1ccc9201f5855d9ebeb42f to your computer and use it in GitHub Desktop.
Can programming be liberated from the ZIO layer style?
/// Powered by TSK - The Scripting Kit https://github.com/tsk-tsk/tsk-tsk 2> /dev/null \\\
/*
export v=0.1.5
. $(b=boot-tsk-$v u=git.io/$b; (cat ~/.tsk/$b || curl -sfL $u || wget -qO - $u) | sh)
scala_version=2.12.13
bloop_version=1.4.11
dependencies='
com.h2database:h2:1.4.199
io.getquill::quill-jdbc-zio:3.8.0
'
run
exit
*/
import com.typesafe.config.ConfigFactory
import io.getquill._
import io.getquill.util.LoadConfig
import io.getquill.context.ZioJdbc._
import io.getquill.context.qzio.ImplicitSyntax._
import zio._
import zio.console._
import java.io.Closeable
import javax.sql.DataSource
import org.h2.tools.RunScript
import java.io.StringReader
import java.sql.SQLException
// Application domain starts here, note lack of ZIO Layer references!
// Also no dependencies are present in the R parameter.
case class Person(name: String, age: Int)
trait PersonRepo {
def select(): IO[SQLException, List[Person]]
}
class PersonRepoH2(ds: DataSource with Closeable) extends PersonRepo {
implicit private val env = Implicit(Has(ds))
private val ctx = new H2ZioJdbcContext(SnakeCase)
import ctx._
def select(): IO[SQLException, List[Person]] =
ctx.run(query[Person].filter(p => p.name == "John")).implicitDS
}
trait PersonService {
def showAllPeople: UIO[Unit]
}
class PersonServiceImpl(repo: PersonRepo, _console: Console) extends PersonService {
def showAllPeople: UIO[Unit] = (for {
people <- repo.select()
_ <- ZIO.foreach(people) { case Person(name, age) =>
putStrLn(s"${name} ${age}").provide(_console)
}
} yield ()).orDie
}
/**
* Wires the whole application together. Look, no layers!
*/
class Application(dataSource: DataSource with Closeable, _console: Console) {
private val personRepo: PersonRepo = new PersonRepoH2(dataSource)
val service: PersonService = new PersonServiceImpl(personRepo, _console)
}
// The first ZIO Layer occurrence, because some libraries ship with their ZLayers (Quill in this case)
object persistence {
private val config =
ConfigFactory.parseString("""
ctx.dataSourceClassName="org.h2.jdbcx.JdbcDataSource"
ctx.dataSource.url="jdbc:h2:mem:yourdbname"
ctx.dataSource.user="sa"
""").getConfig("ctx")
private def createSchema(ds: DataSource with Closeable) =
Task {
RunScript.execute(ds.getConnection, new StringReader("""
CREATE TABLE IF NOT EXISTS Person(
name VARCHAR(255),
age int
);
INSERT INTO Person(name, age) VALUES ('John', 2);
"""))
ds
}
val layer =
(DataSourceLayer.fromConfig(config) >>> ZLayer.fromServiceM(createSchema)).orDie
}
object example extends App {
/**
* Services managed by ZLayers are passed to an object which does the wiring
* in the traditional OOP way (composition root pattern).
*/
val applicationLayer =
ZLayer.fromService[DataSource with Closeable, Application](new Application(_, Has(Console.Service.live)))
def program(app: Application): UIO[ExitCode] =
app.service.showAllPeople.as(ExitCode.success)
override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] =
(ZIO.access[Has[Application]](_.get) >>= program)
.provideLayer(persistence.layer >>> applicationLayer)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment