Skip to content

Instantly share code, notes, and snippets.

View supermanue's full-sized avatar

Manuel Rodríguez Pascual supermanue

View GitHub Profile
@supermanue
supermanue / taggedTypes.scala
Last active April 11, 2022 17:35
Tagged Types
type Tagged[U] = { type Tag = U }
type @@[T, U] = T with Tagged[U]
trait NameTag
trait SurnameTag
type Name = String @@ NameTag
type Surname = String @@ SurnameTag
(...)
@supermanue
supermanue / betterTypeSystem.scala
Created April 11, 2022 17:17
better type system
case class Person(name: Name, surname: Surname)
def getPerson(name: Name, surname: Surname)
val person = Person("manuel", "Rodriguez")
getPerson(person.surname, person.name)
//DOES NOT COMPILE, THANK YOU GODS OF SCALA
getPerson(person.name, person.surname)
@supermanue
supermanue / motivationForTaggedTypes.scala
Created April 11, 2022 17:14
Motivation for Tagged Types
case class Person(name: String, surname: String)
def getPerson(name: String, surname: String): Person = ???
val person = Person("manuel", "rodriguez")
getPerson(person.surname, person.name)
//doesn't find anything because name and surname are in wrong order
object DoobiePersistenceServiceTest extends DefaultRunnableSpec {
def beforeEach: ZIO[DBTransactor, Throwable, Unit] = dropUserTable.flatMap(_ => createUserTable)
def spec: ZSpec[TestEnvironment, Failure] =
suite("DoobiePersistenceService unit test")(
testM("GET should return a UserNotFound if the element does not exist") {
for {
_ <- beforeEach
notFound <- RIO.accessM[UserPersistence](_.get.get(100).either)
@supermanue
supermanue / zlayer.scala
Last active April 5, 2022 07:04
Zlayer
val live: ZLayer[DBTransactor, Throwable, UserPersistence] =
ZLayer.fromService(new DoobiePersistenceService(_))
val transactorLive: ZLayer[Has[DbConfig] with Blocking, Throwable, DBTransactor] =
ZLayer.fromManaged(for {
config <- configuration.dbConfig.toManaged_
connectEC <- ZIO.descriptor.map(_.executor.asEC).toManaged_
blockingEC <- blocking.blocking { ZIO.descriptor.map(_.executor.asEC) }.toManaged_
transactor <- mkTransactor(config, connectEC, blockingEC)
} yield transactor)
@supermanue
supermanue / doobiePersistenceService.scala
Last active April 5, 2022 06:56
Persistence Service
final class DoobiePersistenceService(tnx: Transactor[Task]) extends StoragePort {
import DoobiePersistenceService._
override def create(user: User): IO[AppError, User] =
SQL
.create(UserStored.fromDomainUser(user))
.run
.transact(tnx)
.foldM(err => IO.fail(DBError(err.getMessage)), _ => IO.succeed(user))
import doobie.h2.H2Transactor
import scala.concurrent.ExecutionContext
import zio.Task
import zio.interop.catz._
object DoobiePersistenceService {
def mkTransactor(
conf: DbConfig,
connectEC: ExecutionContext,
@supermanue
supermanue / sqlQueries.scala
Last active April 5, 2022 06:37
SQL Queries
import zio.experiment.adapter.model.{User => UserStored}
object SQL {
def get(id: Int): Query0[UserStored] =
sql"""SELECT * FROM USERS WHERE ID = $id """.query[UserStored]
def create(user: UserStored): Update0 =
sql"""INSERT INTO USERS (id, name) VALUES (${user.id}, ${user.name})""".update
@supermanue
supermanue / User.scala
Created April 5, 2022 06:14
User in adapter layer
import zio.experiment.domain.model.AppError
import zio.experiment.domain.model.User.{ User => UserDomain }
case class User(id: Int, name: String)
object User {
implicit class UserConversions(user: User) {
def toDomainUser: Either[AppError, UserDomain] =
UserDomain.build(user.id, user.name)
}
@supermanue
supermanue / UserAdapter
Created April 5, 2022 06:12
User in apdater layer
import zio.experiment.domain.model.AppError
import zio.experiment.domain.model.User.{ User => UserDomain }
case class User(id: Int, name: String)
object User {
implicit class UserConversions(user: User) {
def toDomainUser: Either[AppError, UserDomain] =
UserDomain.build(user.id, user.name)
}