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 <- list (
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
@@ -195,14 +202,26 @@ set_cache <- function(cache_dir = NULL,
195202# ' [`disable_cache`] to only disable without deleting, and [`cache_info`]
196203# ' @export
197204# ' @import cachem
205+ # ' @importFrom rlang dots_list inject
198206clear_cache <- function (... , disable = FALSE ) {
199207 if (any(! is.na(cache_environ $ epidatr_cache ))) {
200208 cache_environ $ epidatr_cache $ destroy()
209+ recovered_args <- cache_environ $ cache_args
210+ cache_environ $ cache_args <- NULL
211+ } else {
212+ recovered_args <- list ()
201213 }
214+ args <- dots_list(
215+ ... ,
216+ confirm = FALSE ,
217+ !!! recovered_args ,
218+ .homonyms = " first" ,
219+ .ignore_empty = " all"
220+ )
202221 if (disable ) {
203222 cache_environ $ epidatr_cache <- NULL
204223 } else {
205- set_cache(... )
224+ inject( set_cache(!!! args ) )
206225 }
207226}
208227
@@ -234,68 +253,85 @@ disable_cache <- function() {
234253# ' disable without deleting
235254# ' @export
236255cache_info <- function () {
237- if (is.null(cache_environ $ epidatr_cache )) {
238- return (" there is no cache" )
239- } else {
256+ if (is_cache_enabled()) {
240257 return (cache_environ $ epidatr_cache $ info())
258+ } else {
259+ return (" there is no cache" )
241260 }
242261}
243262
244- # ' Dispatch caching
263+ # ' Check if the cache is enabled
264+ # ' @keywords internal
265+ is_cache_enabled <- function () {
266+ ! is.null(cache_environ $ epidatr_cache )
267+ }
268+
269+ # ' Helper that checks whether a call is actually cachable
270+ # '
271+ # ' The cacheable endpoints are those with `as_of` or `issues` parameters:
272+ # ' - pub_covidcast
273+ # ' - pub_covid_hosp_state_timeseries
274+ # ' - pub_ecdc_ili
275+ # ' - pub_flusurv
276+ # ' - pub_fluview_clinical
277+ # ' - pub_fluview
278+ # ' - pub_kcdc_ili
279+ # ' - pub_nidss_flu
280+ # ' - pub_paho_dengue
281+ # '
282+ # ' @keywords internal
283+ check_is_cachable <- function (epidata_call , fetch_args ) {
284+ as_of_cachable <- ! is.null(epidata_call $ params $ as_of ) && ! identical(epidata_call $ params $ as_of , " *" )
285+ issues_cachable <- ! is.null(epidata_call $ params $ issues ) && ! identical(epidata_call $ params $ issues , " *" )
286+ is_cachable <- (
287+ # Cache should be enabled
288+ is_cache_enabled() &&
289+ # Call should be cachable
290+ (as_of_cachable || issues_cachable ) &&
291+ # This should not be a dry run
292+ ! fetch_args $ dry_run &&
293+ # Base url should be null
294+ is.null(fetch_args $ base_url ) &&
295+ # Don't cache debug calls
296+ ! fetch_args $ debug &&
297+ # Format type should be json
298+ fetch_args $ format_type == " json" &&
299+ # Fields should be null
300+ is.null(fetch_args $ fields ) &&
301+ # Disable date parsing should be false
302+ ! fetch_args $ disable_date_parsing &&
303+ # Disable data frame parsing should be false
304+ ! fetch_args $ disable_data_frame_parsing &&
305+ # Refresh cache should be false
306+ fetch_args $ refresh_cache == FALSE
307+ )
308+ return (is_cachable )
309+ }
310+
311+ # ' Check for warnings for the cache
245312# '
246313# ' @description
247- # ' The guts of caching, its interposed between fetch and the specific fetch
248- # ' methods. Internal method only.
314+ # ' Adds warnings when arguments are potentially too recent to use with the cache.
249315# '
250316# ' @param epidata_call the `epidata_call` object
251317# ' @param fetch_args the args list for fetch as generated by [`fetch_args_list()`]
252318# ' @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!).
319+ check_for_cache_warnings <- function (epidata_call , fetch_args ) {
320+ as_of_recent <- check_is_recent(epidata_call $ params $ as_of , 7 )
321+ issues_recent <- check_is_recent(epidata_call $ params $ issues , 7 )
322+ if (as_of_recent || issues_recent ) {
323+ cli :: cli_warn(
324+ c(
325+ " Using cached results with `as_of` within the past week (or the future!).
266326 This will likely result in an invalid cache. Consider" ,
267- " i" = " disabling the cache for this session with `disable_cache` or
327+ " i" = " disabling the cache for this session with `disable_cache` or
268328 permanently with environmental variable `EPIDATR_USE_CACHE=FALSE`" ,
269- " i" = " setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS
329+ " i" = " setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS
270330 ', 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 ))
331+ ),
332+ .frequency = " regularly" ,
333+ .frequency_id = " cache timing issues" ,
334+ class = " cache_recent_data"
335+ )
299336 }
300- return (fetched )
301337}
0 commit comments