Skip to content

Instantly share code, notes, and snippets.

@sdether
Created March 6, 2018 01:42
Show Gist options
  • Save sdether/e3ff27491f0e91c1bcb5103f24ea2d86 to your computer and use it in GitHub Desktop.
Save sdether/e3ff27491f0e91c1bcb5103f24ea2d86 to your computer and use it in GitHub Desktop.
Desugaring Doobie for comprehension
case class Foo(id: Int, name: String)
case class Bar(id: Int, name: String)
case class FooWithBar(foo: Foo, bars: List[Bar])
// The for-comprehension way
def get1(id: Int): ConnectionIO[Option[FooWithBar]] = for {
fooOpt <- sql"""SELECT id, name FROM foo WHERE id=$id""".query[Foo].option
fooOpt2 <- fooOpt match {
case Some(foo) =>
(for {
bars <- sql"""SELECT id,name FROM bar WHERE foo_id=${foo.id}""".query[Bar].to[List]
} yield bars).map { bars =>
Some(FooWithBar(foo, bars))
}
case None => None.pure[ConnectionIO]
}
} yield fooOpt2
// de-sugaring into a flatmap
def get2(id: Int): ConnectionIO[Option[FooWithBar]] = sql"""SELECT id, name FROM foo WHERE id=$id""".query[Foo].option.flatMap {
case Some(foo) =>
sql"""SELECT id,name FROM bar WHERE foo_id=$foo.id""".query[Bar].to[List].map(bars => bars).map(bars =>
Some(FooWithBar(foo, bars)))
// Complains about None.type <: Option[FooWithBar], but class Free is invariant in type A.
case None => None.pure[ConnectionIO]
}
// letting IntelliJ de-sugar the for-comprehension
def get3(id: Int): ConnectionIO[Option[FooWithBar]] = sql"""SELECT id, name FROM foo WHERE id=$id""".query[Foo].option.flatMap(fooOpt => (fooOpt match {
case Some(foo) =>
sql"""SELECT id,name FROM bar WHERE foo_id=$foo.id""".query[Bar].to[List].map(bars => bars).map(bars =>
Some(FooWithBar(foo, bars)))
case None => None.pure[ConnectionIO]
}).map(fooOpt2 => fooOpt2))
// Artificial example using Option[Option[Int] instead of ConnectionIO[Option[FooWithBar]]
// f1 & f2 are equivalent
def f1(x: Option[Option[Int]]): Option[Option[Int]] = x.flatMap {
z =>
(z match {
case Some(y) => Some(Some(y + 1))
case None => Some(None)
}).map(a => a)
}
def f2(x: Option[Option[Int]]): Option[Option[Int]] = x.flatMap {
case Some(y) => Some(Some(y + 1))
case None => Some(None)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment