@@ -9,33 +9,35 @@ import scala.concurrent.{ExecutionContext, Future}
99import scala .util .Try
1010
1111trait Fetching [K , Response ] {
12- def fetch (key : K )( implicit ec : ExecutionContext ) : Future [MissingOrETagged [Response ]]
12+ def fetch (key : K ): Future [MissingOrETagged [Response ]]
1313
14- def fetchOnlyIfETagChanged (key : K , eTag : String )( implicit ec : ExecutionContext ) : Future [Option [MissingOrETagged [Response ]]]
14+ def fetchOnlyIfETagChanged (key : K , eTag : String ): Future [Option [MissingOrETagged [Response ]]]
1515
16+ /**
17+ * @param recordingEC the ExecutionContext used for
18+ */
1619 def timing (
1720 attemptWith : Duration => Unit = _ => (),
1821 successWith : Duration => Unit = _ => (),
1922 fullFetchWith : Duration => Unit = _ => (),
2023 notModifiedWith : Duration => Unit = _ => ()
21- ): Fetching [K , Response ] =
22- DurationRecorder (this ) { recorded =>
23- val duration = recorded.duration
24- attemptWith(duration)
25- recorded.result.foreach { successfulResponse =>
26- successWith(duration)
27- successfulResponse match {
28- case FullFetch => fullFetchWith(duration)
29- case NotModified => notModifiedWith(duration)
30- }
24+ )(implicit recordingEC : ExecutionContext ): Fetching [K , Response ] = DurationRecorder (this ) { recorded =>
25+ val duration = recorded.duration
26+ attemptWith(duration)
27+ recorded.result.foreach { successfulResponse =>
28+ successWith(duration)
29+ successfulResponse match {
30+ case FullFetch => fullFetchWith(duration)
31+ case NotModified => notModifiedWith(duration)
3132 }
3233 }
34+ }
3335
3436 def keyOn [K2 ](f : K2 => K ): Fetching [K2 , Response ] = KeyAdapter (this )(f)
3537
36- def mapResponse [Response2 ](f : Response => Response2 ): Fetching [K , Response2 ] = ResponseMapper (this )(f)
38+ def mapResponse [Response2 ](f : Response => Response2 )( implicit ec : ExecutionContext ) : Fetching [K , Response2 ] = ResponseMapper (this )(f)
3739
38- def thenParsing [V ](parse : Response => V ): Loading [K , V ] = Loading .by(this )(parse)
40+ def thenParsing [V ](parse : Response => V )( implicit parsingEC : ExecutionContext ) : Loading [K , V ] = Loading .by(this )(parse)
3941}
4042
4143object Fetching {
@@ -47,38 +49,44 @@ object Fetching {
4749 object DurationRecorder {
4850 case class Result (duration : Duration , result : Try [SuccessfulFetch ])
4951 }
50- case class DurationRecorder [K , Response ](underlying : Fetching [K , Response ])(recorder : Result => Unit )
52+
53+ /**
54+ * @param ec should recording a result happen on the same thread that
55+ */
56+ case class DurationRecorder [K , Response ](underlying : Fetching [K , Response ])(recorder : Result => Unit )(implicit ec : ExecutionContext )
5157 extends Fetching [K , Response ] {
5258
53- private def time [V ](block : => Future [V ])(f : V => SuccessfulFetch )( implicit ec : ExecutionContext ) : Future [V ] = {
59+ private def time [V ](block : => Future [V ])(f : V => SuccessfulFetch ): Future [V ] = {
5460 val start = Instant .now()
5561 val resultF = block
5662 resultF.onComplete(resultTry => recorder(Result (Duration .between(start, Instant .now()), resultTry.map(f))))
5763 resultF
5864 }
5965
60- override def fetch (key : K )( implicit ec : ExecutionContext ) : Future [MissingOrETagged [Response ]] =
66+ override def fetch (key : K ): Future [MissingOrETagged [Response ]] =
6167 time(underlying.fetch(key))(_ => FullFetch )
6268
63- override def fetchOnlyIfETagChanged (key : K , eTag : String )( implicit ec : ExecutionContext ) : Future [Option [MissingOrETagged [Response ]]] =
69+ override def fetchOnlyIfETagChanged (key : K , eTag : String ): Future [Option [MissingOrETagged [Response ]]] =
6470 time(underlying.fetchOnlyIfETagChanged(key, eTag))(_.map(_ => FullFetch ).getOrElse(NotModified ))
6571 }
6672
6773 private case class KeyAdapter [K , UnderlyingK , Response ](underlying : Fetching [UnderlyingK , Response ])(f : K => UnderlyingK )
6874 extends Fetching [K , Response ] {
69- override def fetch (key : K )( implicit ec : ExecutionContext ) : Future [MissingOrETagged [Response ]] =
75+ override def fetch (key : K ): Future [MissingOrETagged [Response ]] =
7076 underlying.fetch(f(key))
7177
72- override def fetchOnlyIfETagChanged (key : K , eTag : String )( implicit ec : ExecutionContext ) : Future [Option [MissingOrETagged [Response ]]] =
78+ override def fetchOnlyIfETagChanged (key : K , eTag : String ): Future [Option [MissingOrETagged [Response ]]] =
7379 underlying.fetchOnlyIfETagChanged(f(key), eTag)
7480 }
7581
76- private case class ResponseMapper [K , UnderlyingResponse , Response ](underlying : Fetching [K , UnderlyingResponse ])(f : UnderlyingResponse => Response )
82+ private case class ResponseMapper [K , UnderlyingResponse , Response ](underlying : Fetching [K , UnderlyingResponse ])(
83+ f : UnderlyingResponse => Response
84+ )(implicit responseMappingEC : ExecutionContext ) // the function `f` _may_ be resource intensive, and require an appropriate ExecutionContext
7785 extends Fetching [K , Response ] {
78- override def fetch (key : K )( implicit ec : ExecutionContext ) : Future [MissingOrETagged [Response ]] =
86+ override def fetch (key : K ): Future [MissingOrETagged [Response ]] =
7987 underlying.fetch(key).map(_.map(f))
8088
81- override def fetchOnlyIfETagChanged (key : K , eTag : String )( implicit ec : ExecutionContext ) : Future [Option [MissingOrETagged [Response ]]] =
89+ override def fetchOnlyIfETagChanged (key : K , eTag : String ): Future [Option [MissingOrETagged [Response ]]] =
8290 underlying.fetchOnlyIfETagChanged(key, eTag).map(_.map(_.map(f)))
8391 }
8492}
0 commit comments