Last active
June 16, 2019 18:02
-
-
Save ShahOdin/bed148e9482fe6042042bc2c015c3a4b to your computer and use it in GitHub Desktop.
This file contains 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 org.scalatest.{FlatSpec, Matchers} | |
import cats.effect.{ContextShift, IO} | |
import com.dimafeng.testcontainers.{ForAllTestContainer, PostgreSQLContainer} | |
import doobie._ | |
import implicits._ | |
import com.itv.playground.datastore._ | |
import JsonCRUDOps._ | |
import io.circe.{Decoder, Encoder} | |
import scala.concurrent.ExecutionContext | |
object PGObjectUtils{ | |
def jsonMetaCirce[T: Encoder: Decoder: TypeTag]: Meta[T] = | |
Meta.Advanced.other[PGobject]("json").timap[T]( | |
pgO => decode[T](pgO.getValue).leftMap[T](e => throw e).merge)( | |
t => { | |
val o = new PGobject | |
o.setType("json") | |
o.setValue(t.asJson.noSpaces) | |
o | |
} | |
) | |
} | |
class JsonCRUDOps extends FlatSpec with Matchers with ForAllTestContainer { | |
override val container: PostgreSQLContainer = PostgreSQLContainer() | |
implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) | |
private lazy val xa = container.transactor[IO] | |
"Doobie" should "allow inserting data as json, and querying it" in { | |
def insertCardSuitLegacy(cardSuit: CardSuit): ConnectionIO[CardSuit] = { | |
implicit val cardSuitMeta: Meta[CardSuit] = PGObjectUtils.jsonMetaCirce[CardSuit]( | |
CardSuit.encoderById, | |
CardSuit.decoderById, | |
implicitly | |
) | |
sql"insert into suits (suit) values ($cardSuit)" | |
.update | |
.withUniqueGeneratedKeys[CardSuit]("id", "suit") | |
} | |
def insertCardSuit(cardSuit: CardSuit): ConnectionIO[CardSuit] = { | |
implicit val cardSuitMeta: Meta[CardSuit] = PGObjectUtils.jsonMetaCirce[CardSuit]( | |
CardSuit.encoderByName, | |
CardSuit.decoderByName, | |
implicitly | |
) | |
sql"insert into person (suit) values ($cardSuit)" | |
.update | |
.withUniqueGeneratedKeys[CardSuit]("id", "suit") | |
} | |
val query = for { | |
_ <- dropSuit.transact(xa) | |
_ <- createSuit.transact(xa) | |
first <- insertCardSuitLegacy(Hearts).transact(xa) | |
second <- insertCardSuit(Spades).transact(xa) | |
} yield first == Hearts && second == Spades | |
query.attempt.unsafeRunSync() shouldBe Right(true) | |
} | |
} | |
object JsonCRUDOps { | |
import cats.syntax.either._ | |
abstract class CardSuit(val name: String, val id: Short) | |
object CardSuit{ | |
val decoderByName: Decoder[CardSuit] = Decoder[String].emap { | |
case Clubs.name => Clubs.asRight | |
case Diamonds.name => Diamonds.asRight | |
case Hearts.name => Hearts.asRight | |
case Spades.name => Spades.asRight | |
case _ => Left("Card suit stored in an invalid format.") | |
} | |
val encoderByName: Encoder[CardSuit] = Encoder[String].contramap(_.name) | |
val decoderById: Decoder[CardSuit] = Decoder[Short].emap { | |
case Clubs.id => Clubs.asRight | |
case Diamonds.id => Diamonds.asRight | |
case Hearts.id => Hearts.asRight | |
case Spades.id => Spades.asRight | |
case _ => Left("Card suit stored in an invalid format.") | |
} | |
val encoderById: Encoder[CardSuit] = Encoder[Short].contramap(_.id) | |
} | |
case object Clubs extends CardSuit("clubs", 1) | |
case object Diamonds extends CardSuit("diamonds", 2) | |
case object Hearts extends CardSuit("hearts", 3) | |
case object Spades extends CardSuit("spades", 4) | |
val dropSuit: ConnectionIO[Int] = sql""" | |
DROP TABLE IF EXISTS suits | |
""".update.run | |
val createSuit: ConnectionIO[Int] = sql""" | |
CREATE TABLE suits ( | |
id SERIAL NOT NULL UNIQUE, | |
suit JSONB NOT NULL | |
) | |
""".update.run | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment