33cache_environ <- new.env(parent = emptyenv())
44cache_environ $ use_cache <- NULL
55cache_environ $ epidatr_cache <- NULL
6+ cache_environ $ cache_args <- NULL
67
78# ' Create or renew a cache for this session
89# ' @aliases set_cache
@@ -169,6 +170,12 @@ set_cache <- function(cache_dir = NULL,
169170 max_age = days * 24 * 60 * 60 ,
170171 logfile = file.path(cache_dir , logfile )
171172 )
173+ cache_environ $ cache_args <- list2(
174+ cache_dir = cache_dir ,
175+ days = days ,
176+ max_size = max_size ,
177+ logfile = logfile
178+ )
172179 }
173180
174181 cli :: cli_inform(c(
@@ -183,9 +190,9 @@ set_cache <- function(cache_dir = NULL,
183190# ' Manually reset the cache, deleting all currently saved data and starting afresh
184191# ' @description
185192# ' 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 .
189196# ' @param disable instead of setting a new cache, disable caching entirely;
190197# ' defaults to `FALSE`
191198# ' @inheritDotParams set_cache
@@ -198,11 +205,22 @@ set_cache <- function(cache_dir = NULL,
198205clear_cache <- function (... , disable = FALSE ) {
199206 if (any(! is.na(cache_environ $ epidatr_cache ))) {
200207 cache_environ $ epidatr_cache $ destroy()
208+ recovered_args <- cache_environ $ cache_args
209+ cache_environ $ cache_args <- NULL
210+ } else {
211+ recovered_args <- list ()
201212 }
213+ args <- rlang :: dots_list(
214+ ... ,
215+ confirm = FALSE ,
216+ !!! recovered_args ,
217+ .homonyms = " first" ,
218+ .ignore_empty = " all"
219+ )
202220 if (disable ) {
203221 cache_environ $ epidatr_cache <- NULL
204222 } else {
205- set_cache(... )
223+ rlang :: inject( set_cache(!!! args ) )
206224 }
207225}
208226
@@ -234,68 +252,85 @@ disable_cache <- function() {
234252# ' disable without deleting
235253# ' @export
236254cache_info <- function () {
237- if (is.null(cache_environ $ epidatr_cache )) {
238- return (" there is no cache" )
239- } else {
255+ if (is_cache_enabled()) {
240256 return (cache_environ $ epidatr_cache $ info())
257+ } else {
258+ return (" there is no cache" )
241259 }
242260}
243261
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
245311# '
246312# ' @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.
249314# '
250315# ' @param epidata_call the `epidata_call` object
251316# ' @param fetch_args the args list for fetch as generated by [`fetch_args_list()`]
252317# ' @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!).
266325 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
268327 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
270329 ', 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+ )
299335 }
300- return (fetched )
301336}
0 commit comments