@@ -74,13 +74,13 @@ import cats.implicits._
74
74
75
75
import fetch ._
76
76
77
- def latency [F [_] : Concurrent ](milis : Long ): F [Unit ] =
78
- Concurrent [F ].delay(Thread .sleep(milis))
77
+ def latency [F [_] : Sync ](milis : Long ): F [Unit ] =
78
+ Sync [F ].delay(Thread .sleep(milis))
79
79
80
80
object ToString extends Data [Int , String ] {
81
81
def name = " To String"
82
82
83
- def source [F [_] : Concurrent ]: DataSource [F , Int , String ] = new DataSource [F , Int , String ]{
83
+ def source [F [_] : Async ]: DataSource [F , Int , String ] = new DataSource [F , Int , String ]{
84
84
override def data = ToString
85
85
86
86
override def CF = Concurrent [F ]
@@ -99,7 +99,7 @@ object ToString extends Data[Int, String] {
99
99
}
100
100
}
101
101
102
- def fetchString [F [_] : Concurrent ](n : Int ): Fetch [F , String ] =
102
+ def fetchString [F [_] : Async ](n : Int ): Fetch [F , String ] =
103
103
Fetch (n, ToString .source)
104
104
```
105
105
@@ -116,16 +116,15 @@ import scala.concurrent.ExecutionContext
116
116
val executor = new ScheduledThreadPoolExecutor (4 )
117
117
val executionContext : ExecutionContext = ExecutionContext .fromExecutor(executor)
118
118
119
- implicit val timer : Timer [IO ] = IO .timer(executionContext)
120
- implicit val cs : ContextShift [IO ] = IO .contextShift(executionContext)
119
+ import cats .effect .unsafe .implicits .global
121
120
```
122
121
123
122
## Creating and running a fetch
124
123
125
124
Now that we can convert ` Int ` values to ` Fetch[F, String] ` , let's try creating a fetch.
126
125
127
126
``` scala
128
- def fetchOne [F [_] : Concurrent ]: Fetch [F , String ] =
127
+ def fetchOne [F [_] : Async ]: Fetch [F , String ] =
129
128
fetchString(1 )
130
129
```
131
130
@@ -135,8 +134,8 @@ Let's run it and wait for the fetch to complete. We'll use `IO#unsafeRunTimed` f
135
134
import scala .concurrent .duration ._
136
135
137
136
Fetch .run[IO ](fetchOne).unsafeRunTimed(5 .seconds)
138
- // --> [236 ] One ToString 1
139
- // <-- [236 ] One ToString 1
137
+ // --> [771 ] One ToString 1
138
+ // <-- [771 ] One ToString 1
140
139
// res0: Option[String] = Some(value = "1")
141
140
```
142
141
@@ -147,16 +146,16 @@ As you can see in the previous example, the `ToStringSource` is queried once to
147
146
Multiple fetches to the same data source are automatically batched. For illustrating this, we are going to compose three independent fetch results as a tuple.
148
147
149
148
``` scala
150
- def fetchThree [F [_] : Concurrent ]: Fetch [F , (String , String , String )] =
149
+ def fetchThree [F [_] : Async ]: Fetch [F , (String , String , String )] =
151
150
(fetchString(1 ), fetchString(2 ), fetchString(3 )).tupled
152
151
```
153
152
154
153
When executing the above fetch, note how the three identities get batched, and the data source is only queried once.
155
154
156
155
``` scala
157
156
Fetch .run[IO ](fetchThree).unsafeRunTimed(5 .seconds)
158
- // --> [236 ] Batch ToString NonEmptyList(1, 2, 3)
159
- // <-- [236 ] Batch ToString NonEmptyList(1, 2, 3)
157
+ // --> [777 ] Batch ToString NonEmptyList(1, 2, 3)
158
+ // <-- [777 ] Batch ToString NonEmptyList(1, 2, 3)
160
159
// res1: Option[(String, String, String)] = Some(value = ("1", "2", "3"))
161
160
```
162
161
@@ -166,7 +165,7 @@ Note that the `DataSource#batch` method is not mandatory. It will be implemented
166
165
object UnbatchedToString extends Data [Int , String ] {
167
166
def name = " Unbatched to string"
168
167
169
- def source [F [_] : Concurrent ] = new DataSource [F , Int , String ] {
168
+ def source [F [_]: Async ] = new DataSource [F , Int , String ] {
170
169
override def data = UnbatchedToString
171
170
172
171
override def CF = Concurrent [F ]
@@ -179,27 +178,27 @@ object UnbatchedToString extends Data[Int, String] {
179
178
}
180
179
}
181
180
182
- def unbatchedString [F [_] : Concurrent ](n : Int ): Fetch [F , String ] =
181
+ def unbatchedString [F [_]: Async ](n : Int ): Fetch [F , String ] =
183
182
Fetch (n, UnbatchedToString .source)
184
183
```
185
184
186
185
Let's create a tuple of unbatched string requests.
187
186
188
187
``` scala
189
- def fetchUnbatchedThree [F [_] : Concurrent ]: Fetch [F , (String , String , String )] =
188
+ def fetchUnbatchedThree [F [_] : Async ]: Fetch [F , (String , String , String )] =
190
189
(unbatchedString(1 ), unbatchedString(2 ), unbatchedString(3 )).tupled
191
190
```
192
191
193
192
When executing the above fetch, note how the three identities get requested in parallel. You can override ` batch ` to execute queries sequentially if you need to.
194
193
195
194
``` scala
196
195
Fetch .run[IO ](fetchUnbatchedThree).unsafeRunTimed(5 .seconds)
197
- // --> [236 ] One UnbatchedToString 1
198
- // --> [237 ] One UnbatchedToString 2
199
- // --> [238 ] One UnbatchedToString 3
200
- // <-- [236 ] One UnbatchedToString 1
201
- // <-- [237 ] One UnbatchedToString 2
202
- // <-- [238 ] One UnbatchedToString 3
196
+ // --> [778 ] One UnbatchedToString 1
197
+ // --> [776 ] One UnbatchedToString 2
198
+ // --> [777 ] One UnbatchedToString 3
199
+ // <-- [776 ] One UnbatchedToString 2
200
+ // <-- [777 ] One UnbatchedToString 3
201
+ // <-- [778 ] One UnbatchedToString 1
203
202
// res2: Option[(String, String, String)] = Some(value = ("1", "2", "3"))
204
203
```
205
204
@@ -211,7 +210,7 @@ If we combine two independent fetches from different data sources, the fetches c
211
210
object Length extends Data [String , Int ] {
212
211
def name = " Length"
213
212
214
- def source [F [_] : Concurrent ] = new DataSource [F , String , Int ] {
213
+ def source [F [_] : Async ] = new DataSource [F , String , Int ] {
215
214
override def data = Length
216
215
217
216
override def CF = Concurrent [F ]
@@ -230,25 +229,25 @@ object Length extends Data[String, Int] {
230
229
}
231
230
}
232
231
233
- def fetchLength [F [_] : Concurrent ](s : String ): Fetch [F , Int ] =
232
+ def fetchLength [F [_] : Async ](s : String ): Fetch [F , Int ] =
234
233
Fetch (s, Length .source)
235
234
```
236
235
237
236
And now we can easily receive data from the two sources in a single fetch.
238
237
239
238
``` scala
240
- def fetchMulti [F [_] : Concurrent ]: Fetch [F , (String , Int )] =
239
+ def fetchMulti [F [_] : Async ]: Fetch [F , (String , Int )] =
241
240
(fetchString(1 ), fetchLength(" one" )).tupled
242
241
```
243
242
244
243
Note how the two independent data fetches run in parallel, minimizing the latency cost of querying the two data sources.
245
244
246
245
``` scala
247
246
Fetch .run[IO ](fetchMulti).unsafeRunTimed(5 .seconds)
248
- // --> [239 ] One Length one
249
- // --> [236 ] One ToString 1
250
- // <-- [239 ] One Length one
251
- // <-- [236 ] One ToString 1
247
+ // --> [774 ] One ToString 1
248
+ // --> [777 ] One Length one
249
+ // <-- [774 ] One ToString 1
250
+ // <-- [777 ] One Length one
252
251
// res3: Option[(String, Int)] = Some(value = ("1", 3))
253
252
```
254
253
@@ -261,7 +260,7 @@ When fetching an identity twice within the same `Fetch`, such as a batch of fetc
261
260
Let's try creating a fetch that asks for the same identity twice, by using ` flatMap ` (in a for-comprehension) to chain the requests together:
262
261
263
262
``` scala
264
- def fetchTwice [F [_] : Concurrent ]: Fetch [F , (String , String )] = for {
263
+ def fetchTwice [F [_] : Async ]: Fetch [F , (String , String )] = for {
265
264
one <- fetchString(1 )
266
265
two <- fetchString(1 )
267
266
} yield (one, two)
@@ -275,16 +274,16 @@ val runFetchTwice = Fetch.run[IO](fetchTwice)
275
274
```
276
275
``` scala
277
276
runFetchTwice.unsafeRunTimed(5 .seconds)
278
- // --> [237 ] One ToString 1
279
- // <-- [237 ] One ToString 1
277
+ // --> [772 ] One ToString 1
278
+ // <-- [772 ] One ToString 1
280
279
// res4: Option[(String, String)] = Some(value = ("1", "1"))
281
280
```
282
281
283
282
This will still fetch the data again, however, if we call it once more:
284
283
``` scala
285
284
runFetchTwice.unsafeRunTimed(5 .seconds)
286
- // --> [239 ] One ToString 1
287
- // <-- [239 ] One ToString 1
285
+ // --> [778 ] One ToString 1
286
+ // <-- [778 ] One ToString 1
288
287
// res5: Option[(String, String)] = Some(value = ("1", "1"))
289
288
```
290
289
@@ -302,8 +301,8 @@ val runFetchFourTimesSharedCache = for {
302
301
```
303
302
``` scala
304
303
runFetchFourTimesSharedCache.unsafeRunTimed(5 .seconds)
305
- // --> [238 ] One ToString 1
306
- // <-- [238 ] One ToString 1
304
+ // --> [777 ] One ToString 1
305
+ // <-- [777 ] One ToString 1
307
306
// res6: Option[(String, String, String, String)] = Some(
308
307
// value = ("1", "1", "1", "1")
309
308
// )
0 commit comments