@@ -18,16 +18,15 @@ package fetch
1818
1919import org .scalatest .{AsyncFreeSpec , Matchers }
2020
21- import fetch ._
22-
2321import scala .concurrent ._
2422import scala .concurrent .duration ._
2523
2624import cats ._
25+ import cats .temp .par ._
2726import cats .effect ._
2827import cats .instances .list ._
28+ import cats .instances .option ._
2929import cats .data .NonEmptyList
30- import cats .syntax .cartesian ._
3130import cats .syntax .all ._
3231
3332class FetchTests extends AsyncFreeSpec with Matchers {
@@ -717,4 +716,65 @@ class FetchTests extends AsyncFreeSpec with Matchers {
717716 case Left (MissingIdentity (Never (), _, _)) =>
718717 }).unsafeToFuture
719718 }
719+
720+ // Optional fetches
721+
722+ case class MaybeMissing (id : Int )
723+
724+ object MaybeMissingSource extends DataSource [MaybeMissing , Int ] {
725+ override def name = " Maybe Missing Source"
726+
727+ override def fetch [F [_]](id : MaybeMissing )(
728+ implicit CF : ConcurrentEffect [F ], P : Par [F ]
729+ ): F [Option [Int ]] =
730+ if (id.id % 2 == 0 )
731+ Applicative [F ].pure(None )
732+ else
733+ Applicative [F ].pure(Option (id.id))
734+ }
735+
736+ def maybeOpt [F [_] : ConcurrentEffect ](id : Int ): Fetch [F , Option [Int ]] =
737+ Fetch .optional(MaybeMissing (id), MaybeMissingSource )
738+
739+ " We can run optional fetches" in {
740+ def fetch [F [_] : ConcurrentEffect ]: Fetch [F , Option [Int ]] =
741+ maybeOpt(1 )
742+
743+ Fetch .run[IO ](fetch).map(_ shouldEqual Some (1 )).unsafeToFuture
744+ }
745+
746+ " We can run optional fetches with traverse" in {
747+ def fetch [F [_] : ConcurrentEffect ]: Fetch [F , List [Int ]] =
748+ List (1 , 2 , 3 ).traverse(maybeOpt[F ]).map(_.flatten)
749+
750+ Fetch .run[IO ](fetch).map(_ shouldEqual List (1 , 3 )).unsafeToFuture
751+ }
752+
753+ " We can run optional fetches with other data sources" in {
754+ def fetch [F [_] : ConcurrentEffect ]: Fetch [F , List [Int ]] = {
755+ val ones = List (1 , 2 , 3 ).traverse(one[F ])
756+ val maybes = List (1 , 2 , 3 ).traverse(maybeOpt[F ])
757+ (ones, maybes).mapN { case (os, ms) => os ++ ms.flatten }
758+ }
759+
760+ Fetch .run[IO ](fetch).map(_ shouldEqual List (1 , 2 , 3 , 1 , 3 )).unsafeToFuture
761+ }
762+
763+ " We can make fetches that depend on optional fetch results when they aren't defined" in {
764+ def fetch [F [_] : ConcurrentEffect ]: Fetch [F , Int ] = for {
765+ maybe <- maybeOpt(2 )
766+ result <- maybe.fold(Fetch .pure(42 ))(i => one(i))
767+ } yield result
768+
769+ Fetch .run[IO ](fetch).map(_ shouldEqual 42 ).unsafeToFuture
770+ }
771+
772+ " We can make fetches that depend on optional fetch results when they are defined" in {
773+ def fetch [F [_] : ConcurrentEffect ]: Fetch [F , Int ] = for {
774+ maybe <- maybeOpt(1 )
775+ result <- maybe.fold(Fetch .pure(42 ))(i => one(i))
776+ } yield result
777+
778+ Fetch .run[IO ](fetch).map(_ shouldEqual 1 ).unsafeToFuture
779+ }
720780}
0 commit comments