Last active
February 5, 2019 21:20
-
-
Save mielientiev/3b2b37a0fe4db15f93df7ccd9cf39213 to your computer and use it in GitHub Desktop.
Slick Final Tagless approach
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
// build.sbt | |
val slick = Seq( | |
"com.typesafe.slick" %% "slick" % "3.2.1", | |
"org.slf4j" % "slf4j-nop" % "1.6.4", | |
"com.typesafe.slick" %% "slick-hikaricp" % "3.2.1", | |
"com.h2database" % "h2" % "1.4.196" | |
) | |
val scalaz = Seq( | |
"org.scalaz" %% "scalaz-core" % "7.2.17" | |
) | |
libraryDependencies ++= slick ++ scalaz | |
---------- | |
// resources/application.conf | |
h2mem = { | |
url = "jdbc:h2:mem:test1" | |
driver = org.h2.Driver | |
connectionPool = disabled | |
keepAliveConnection = true | |
} | |
---------- | |
//Product.scala | |
case class Product(id: Option[Int], name: String) | |
---------- | |
//ProductDao.scala | |
trait ProductDao[F[_]] { | |
def create: F[Unit] | |
def findByName(name: String): F[Option[Product]] | |
def save(product: Product): F[Product] | |
} | |
---------- | |
//SlickProductDao.scala | |
import slick.dbio._ | |
import slick.jdbc.JdbcProfile | |
class SlickProductDao(val jdbcProfile: JdbcProfile) extends ProductDao[DBIO] { | |
import jdbcProfile.api._ | |
class ProductTable(tag: Tag) extends Table[Product](tag, "Product") { | |
def id = column[Int]("ID", O.PrimaryKey, O.AutoInc) | |
def name = column[String]("NAME") | |
override def * = (id.?, name) <> (Product.tupled, Product.unapply) | |
} | |
val productTable = TableQuery[ProductTable] | |
override def findByName(name: String): DBIO[Option[Product]] = productTable.filter(_.name === name).result.headOption | |
override def save(product: Product): DBIO[Product] = (productTable returning productTable.map(_.id) | |
into ((savedProduct,id) => savedProduct.copy(id=Some(id))) | |
) += product | |
override def create: DBIO[Unit] = productTable.schema.create | |
} | |
---------- | |
//ProductService.scala | |
trait ProductService[F[_]] { | |
def findByNameOrSave(product: Product): F[Product] | |
} | |
---------- | |
//DefaultProductService.scala | |
import scala.concurrent.ExecutionContext | |
import scalaz.{Monad, OptionT, ~>} | |
class DefaultProductService[F[_]: Monad, DB[_]: Monad](productDao: ProductDao[DB], execute: DB ~> F) extends ProductService[F] { | |
override def findByNameOrSave(product: Product): F[Product] = { | |
val result: DB[Product] = | |
OptionT(productDao.findByName(product.name)) | |
.getOrElseF(productDao.save(product)) | |
execute.apply(result) | |
} | |
} | |
----------- | |
// dbio.scala | |
trait DBIOInstances { | |
implicit def instance(implicit ec: ExecutionContext): Monad[DBIO] = new Monad[DBIO] { | |
override def bind[A, B](fa: DBIO[A])(f: A => DBIO[B]) = fa.flatMap(f) | |
override def point[A](a: => A): DBIO[A] = DBIO.successful(a) | |
} | |
} | |
object dbio extends DBIOInstances | |
--------- | |
// Main.scala | |
import slick.dbio._ | |
import slick.jdbc.{H2Profile, JdbcBackend, JdbcProfile} | |
import slick.jdbc.JdbcBackend.Database | |
import scala.concurrent.duration.Duration | |
import scala.concurrent.{Await, ExecutionContext, Future} | |
import scalaz._ | |
import scalaz.Scalaz._ | |
import dbio._ | |
object Main { | |
def main(args: Array[String]): Unit = { | |
implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global | |
val h2db: JdbcBackend.Database = Database.forConfig("h2mem") | |
val productDao = new SlickProductDao(H2Profile) | |
val dBIOTransformer = dBIOTransformation(H2Profile, h2db) | |
val service = new DefaultProductService[Future, DBIO](productDao, dBIOTransformer) | |
Await.result(dBIOTransformer(productDao.create), Duration.Inf) | |
println(Await.result(service.findByNameOrSave(Product(None, "abc")), Duration.Inf)) | |
println(Await.result(service.findByNameOrSave(Product(None, "abc")), Duration.Inf)) | |
} | |
private def dBIOTransformation(profile: JdbcProfile, db: JdbcBackend.Database): DBIO ~> Future = new (DBIO ~> Future) { | |
import profile.api._ | |
override def apply[A](fa: DBIO[A]): Future[A] = db.run(fa.transactionally) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment