3
3
cache_environ <- new.env(parent = emptyenv())
4
4
cache_environ $ use_cache <- NULL
5
5
cache_environ $ epidatr_cache <- NULL
6
+ cache_environ $ cache_args <- NULL
6
7
7
8
# ' Create or renew a cache for this session
8
9
# ' @aliases set_cache
@@ -169,6 +170,12 @@ set_cache <- function(cache_dir = NULL,
169
170
max_age = days * 24 * 60 * 60 ,
170
171
logfile = file.path(cache_dir , logfile )
171
172
)
173
+ cache_environ $ cache_args <- list2(
174
+ cache_dir = cache_dir ,
175
+ days = days ,
176
+ max_size = max_size ,
177
+ logfile = logfile
178
+ )
172
179
}
173
180
174
181
cli :: cli_inform(c(
@@ -183,9 +190,9 @@ set_cache <- function(cache_dir = NULL,
183
190
# ' Manually reset the cache, deleting all currently saved data and starting afresh
184
191
# ' @description
185
192
# ' Deletes the current cache and resets a new cache. Deletes local data! If you
186
- # ' are using a session unique cache, you will have to pass the arguments you
187
- # ' used for `set_cache` earlier, otherwise the system-wide `.Renviron`-based
188
- # ' defaults will be used .
193
+ # ' are using a session unique cache, the previous settings will be reused. If
194
+ # ' you pass in new `set_cache` arguments, they will take precedence over the
195
+ # ' previous settings .
189
196
# ' @param disable instead of setting a new cache, disable caching entirely;
190
197
# ' defaults to `FALSE`
191
198
# ' @inheritDotParams set_cache
@@ -198,11 +205,22 @@ set_cache <- function(cache_dir = NULL,
198
205
clear_cache <- function (... , disable = FALSE ) {
199
206
if (any(! is.na(cache_environ $ epidatr_cache ))) {
200
207
cache_environ $ epidatr_cache $ destroy()
208
+ recovered_args <- cache_environ $ cache_args
209
+ cache_environ $ cache_args <- NULL
210
+ } else {
211
+ recovered_args <- list ()
201
212
}
213
+ args <- rlang :: dots_list(
214
+ ... ,
215
+ confirm = FALSE ,
216
+ !!! recovered_args ,
217
+ .homonyms = " first" ,
218
+ .ignore_empty = " all"
219
+ )
202
220
if (disable ) {
203
221
cache_environ $ epidatr_cache <- NULL
204
222
} else {
205
- set_cache(... )
223
+ rlang :: inject( set_cache(!!! args ) )
206
224
}
207
225
}
208
226
@@ -234,68 +252,85 @@ disable_cache <- function() {
234
252
# ' disable without deleting
235
253
# ' @export
236
254
cache_info <- function () {
237
- if (is.null(cache_environ $ epidatr_cache )) {
238
- return (" there is no cache" )
239
- } else {
255
+ if (is_cache_enabled()) {
240
256
return (cache_environ $ epidatr_cache $ info())
257
+ } else {
258
+ return (" there is no cache" )
241
259
}
242
260
}
243
261
244
- # ' Dispatch caching
262
+ # ' Check if the cache is enabled
263
+ # ' @keywords internal
264
+ is_cache_enabled <- function () {
265
+ ! is.null(cache_environ $ epidatr_cache )
266
+ }
267
+
268
+ # ' Helper that checks whether a call is actually cachable
269
+ # '
270
+ # ' The cacheable endpoints are those with `as_of` or `issues` parameters:
271
+ # ' - pub_covidcast
272
+ # ' - pub_covid_hosp_state_timeseries
273
+ # ' - pub_ecdc_ili
274
+ # ' - pub_flusurv
275
+ # ' - pub_fluview_clinical
276
+ # ' - pub_fluview
277
+ # ' - pub_kcdc_ili
278
+ # ' - pub_nidss_flu
279
+ # ' - pub_paho_dengue
280
+ # '
281
+ # ' @keywords internal
282
+ check_is_cachable <- function (epidata_call , fetch_args ) {
283
+ as_of_cachable <- ! is.null(epidata_call $ params $ as_of ) && ! identical(epidata_call $ params $ as_of , " *" )
284
+ issues_cachable <- ! is.null(epidata_call $ params $ issues ) && ! identical(epidata_call $ params $ issues , " *" )
285
+ is_cachable <- (
286
+ # Cache should be enabled
287
+ is_cache_enabled() &&
288
+ # Call should be cachable
289
+ (as_of_cachable || issues_cachable ) &&
290
+ # This should not be a dry run
291
+ ! fetch_args $ dry_run &&
292
+ # Base url should be null
293
+ is.null(fetch_args $ base_url ) &&
294
+ # Don't cache debug calls
295
+ ! fetch_args $ debug &&
296
+ # Format type should be json
297
+ fetch_args $ format_type == " json" &&
298
+ # Fields should be null
299
+ is.null(fetch_args $ fields ) &&
300
+ # Disable date parsing should be false
301
+ ! fetch_args $ disable_date_parsing &&
302
+ # Disable data frame parsing should be false
303
+ ! fetch_args $ disable_data_frame_parsing &&
304
+ # Refresh cache should be false
305
+ fetch_args $ refresh_cache == FALSE
306
+ )
307
+ return (is_cachable )
308
+ }
309
+
310
+ # ' Check for warnings for the cache
245
311
# '
246
312
# ' @description
247
- # ' The guts of caching, its interposed between fetch and the specific fetch
248
- # ' methods. Internal method only.
313
+ # ' Adds warnings when arguments are potentially too recent to use with the cache.
249
314
# '
250
315
# ' @param epidata_call the `epidata_call` object
251
316
# ' @param fetch_args the args list for fetch as generated by [`fetch_args_list()`]
252
317
# ' @keywords internal
253
- # ' @importFrom openssl md5
254
- cache_epidata_call <- function (epidata_call , fetch_args = fetch_args_list()) {
255
- is_cachable <- check_is_cachable(epidata_call , fetch_args )
256
- if (is_cachable ) {
257
- target <- request_url(epidata_call )
258
- hashed <- md5(target )
259
- cached <- cache_environ $ epidatr_cache $ get(hashed )
260
- as_of_recent <- check_is_recent(epidata_call $ params $ as_of , 7 )
261
- issues_recent <- check_is_recent(epidata_call $ params $ issues , 7 )
262
- if (as_of_recent || issues_recent ) {
263
- cli :: cli_warn(
264
- c(
265
- " Using cached results with `as_of` within the past week (or the future!).
318
+ check_for_cache_warnings <- function (epidata_call , fetch_args ) {
319
+ as_of_recent <- check_is_recent(epidata_call $ params $ as_of , 7 )
320
+ issues_recent <- check_is_recent(epidata_call $ params $ issues , 7 )
321
+ if (as_of_recent || issues_recent ) {
322
+ cli :: cli_warn(
323
+ c(
324
+ " Using cached results with `as_of` within the past week (or the future!).
266
325
This will likely result in an invalid cache. Consider" ,
267
- " i" = " disabling the cache for this session with `disable_cache` or
326
+ " i" = " disabling the cache for this session with `disable_cache` or
268
327
permanently with environmental variable `EPIDATR_USE_CACHE=FALSE`" ,
269
- " i" = " setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS
328
+ " i" = " setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS
270
329
', unset = 1)}` to e.g. `3/24` (3 hours)."
271
- ),
272
- .frequency = " regularly" ,
273
- .frequency_id = " cache timing issues" ,
274
- class = " cache_recent_data"
275
- )
276
- }
277
- if (! is.key_missing(cached )) {
278
- cli :: cli_warn(
279
- c(
280
- " Loading from the cache at {cache_environ$epidatr_cache$info()$dir};
281
- see {cache_environ$epidatr_cache$info()$logfile} for more details."
282
- ),
283
- .frequency = " regularly" ,
284
- .frequency_id = " using the cache" ,
285
- class = " cache_access"
286
- )
287
- return (cached [[1 ]])
288
- }
289
- }
290
- # need to actually get the data, since its either not in the cache or we're not caching
291
- runtime <- system.time(if (epidata_call $ only_supports_classic ) {
292
- fetched <- fetch_classic(epidata_call , fetch_args )
293
- } else {
294
- fetched <- fetch_tbl(epidata_call , fetch_args )
295
- })
296
- # add it to the cache if appropriate
297
- if (is_cachable ) {
298
- cache_environ $ epidatr_cache $ set(hashed , list (fetched , Sys.time(), runtime ))
330
+ ),
331
+ .frequency = " regularly" ,
332
+ .frequency_id = " cache timing issues" ,
333
+ class = " cache_recent_data"
334
+ )
299
335
}
300
- return (fetched )
301
336
}
0 commit comments