From 0b4390ead71a5b04ce7f39ecd7562e67b26b74bd Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Thu, 25 Apr 2019 14:53:47 +0200 Subject: [PATCH 1/2] Lift Concurrent actions to Fetch Closes #188 --- shared/src/main/scala/fetch.scala | 15 ++++++++- shared/src/test/scala/FetchTests.scala | 43 ++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/shared/src/main/scala/fetch.scala b/shared/src/main/scala/fetch.scala index f3a571d5..62c35503 100644 --- a/shared/src/main/scala/fetch.scala +++ b/shared/src/main/scala/fetch.scala @@ -39,7 +39,10 @@ object `package` { private[fetch] final case class FetchOne[I, A](id: I, data: Data[I, A]) extends FetchQuery[I, A] { override def identities: NonEmptyList[I] = NonEmptyList.one(id) } - private[fetch] final case class Batch[I, A](ids: NonEmptyList[I], data: Data[I, A]) extends FetchQuery[I, A] { override def identities: NonEmptyList[I] = ids } + private[fetch] final case class Batch[I, A](ids: NonEmptyList[I], data: Data[I, A]) extends FetchQuery[I, A] { + override def identities: NonEmptyList[I] = ids + } + // Fetch result states private[fetch] sealed trait FetchStatus extends Product with Serializable @@ -316,6 +319,16 @@ object `package` { } } yield result) + def liftF[F[_] : Concurrent, A](f: F[A]): Fetch[F, A] = + Unfetch[F, A](for { + either <- f.attempt + result = either match { + case Left(err) => Throw[F, A](log => UnhandledException(err, log)) + case Right(r) => Done[F, A](r) + } + } yield result) + + // Running a Fetch /** diff --git a/shared/src/test/scala/FetchTests.scala b/shared/src/test/scala/FetchTests.scala index 7a252302..40ca3315 100644 --- a/shared/src/test/scala/FetchTests.scala +++ b/shared/src/test/scala/FetchTests.scala @@ -884,4 +884,47 @@ class FetchTests extends FetchSpec { io.map(_ shouldEqual List(0, 1, 2, 42)).unsafeToFuture } + + // Concurrent[_] in Fetch + + + "We can lift Concurrent actions into Fetch" in { + def fortyTwo[F[_] : Concurrent]: F[Int] = + Concurrent[F].pure(42) + + def fetch[F[_] : ConcurrentEffect]: Fetch[F, Int] = + Fetch.liftF(fortyTwo) + + Fetch.run[IO](fetch).map(_ shouldEqual 42).unsafeToFuture + } + + "A failed Concurrent action lifted into Fetch will cause a Fetch to fail" in { + def fail[F[_] : Concurrent]: F[Int] = + Concurrent[F].raiseError(AnException()) + + def fetch[F[_] : ConcurrentEffect]: Fetch[F, Int] = + Fetch.liftF(fail) + + val io = Fetch.run[IO](fetch) + + io.attempt + .map(_ should matchPattern { + case Left(UnhandledException(AnException(), _)) => + }).unsafeToFuture + } + + "A Concurrent action can be combined with data fetches" in { + def concurrently[F[_] : Concurrent, A](x: A): F[A] = + Concurrent[F].pure(x) + + def fetch[F[_] : ConcurrentEffect]: Fetch[F, List[Int]] = for { + x <- Fetch.liftF(concurrently(3)) + manies <- many(x) + (ones, y) <- (manies.traverse(one[F]), Fetch.liftF(concurrently(42))).tupled + } yield ones :+ y + + val io = Fetch.run[IO](fetch) + + io.map(_ shouldEqual List(0, 1, 2, 42)).unsafeToFuture + } } From 362b97f31836aa10c75bed0a0b28a99ac2d295a2 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Thu, 25 Apr 2019 17:15:48 +0200 Subject: [PATCH 2/2] Avoid single-line for comprehensions --- shared/src/main/scala/fetch.scala | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/shared/src/main/scala/fetch.scala b/shared/src/main/scala/fetch.scala index 62c35503..92058dc5 100644 --- a/shared/src/main/scala/fetch.scala +++ b/shared/src/main/scala/fetch.scala @@ -311,22 +311,20 @@ object `package` { ) def liftIO[F[_] : ConcurrentEffect, A](io: IO[A]): Fetch[F, A] = - Unfetch[F, A](for { - either <- ConcurrentEffect[F].liftIO(io).attempt - result = either match { + Unfetch[F, A]( + ConcurrentEffect[F].liftIO(io).attempt.map { case Left(err) => Throw[F, A](log => UnhandledException(err, log)) case Right(r) => Done[F, A](r) } - } yield result) + ) def liftF[F[_] : Concurrent, A](f: F[A]): Fetch[F, A] = - Unfetch[F, A](for { - either <- f.attempt - result = either match { + Unfetch[F, A]( + f.attempt.map { case Left(err) => Throw[F, A](log => UnhandledException(err, log)) case Right(r) => Done[F, A](r) } - } yield result) + ) // Running a Fetch