Skip to content

Commit

Permalink
implement disk caching of API calls using memoise::memoise()
Browse files Browse the repository at this point in the history
- caching enabled by default, for 30 days
- add `use_cache = FALSE` to most dataverse functions to temporarily disable
  use
- set environment variable DATAVERSE_USE_CACHE to FALSE to disable across
  function calls
  • Loading branch information
mtmorgan committed Sep 15, 2024
1 parent 50d285e commit 27787ab
Show file tree
Hide file tree
Showing 31 changed files with 192 additions and 90 deletions.
3 changes: 3 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ Authors@R:
Imports:
checkmate,
httr,
memoise,
cachem,
jsonlite,
readr,
stats,
utils,
tools,
xml2
Suggests:
covr,
Expand Down
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ export(service_document)
export(set_dataverse_metadata)
export(update_dataset)
export(update_dataset_file)
importFrom(cachem,cache_disk)
importFrom(checkmate,assert_character)
importFrom(checkmate,assert_logical)
importFrom(memoise,memoise)
29 changes: 25 additions & 4 deletions R/onload.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
#' @importFrom cachem cache_disk
#'
#' @importFrom memoise memoise
.onLoad <- function(libname, pkgname) {
# a <- Sys.getenv("DATAVERSE_SERVER")
# if(a == "") {
# Sys.setenv("DATAVERSE_SERVER" = "dataverse.harvard.edu")
# }
# a <- Sys.getenv("DATAVERSE_SERVER")
# if(a == "") {
# Sys.setenv("DATAVERSE_SERVER" = "dataverse.harvard.edu")
# }

## implement API disk cache via 'memoise'
cache_directory <- file.path(
tools::R_user_dir(pkgname, "cache"),
"api_cache"
)
get <- api_get_impl
if (!dir.exists(cache_directory)) {
status <- dir.create(cache_directory, recursive = TRUE)
if (!status)
warning("'dataverse' failed to create API cache")
}
if (dir.exists(cache_directory)) {
# disk cache with max age 30 days
cache <- cache_disk(cache_directory, max_age = 60 * 60 * 24 * 30)
get <- memoise(get, cache = cache)
}
api_get_memoized <<- get
}
30 changes: 24 additions & 6 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,32 @@ api_url <- function(server = Sys.getenv("DATAVERSE_SERVER"), prefix = "api/") {
}

## common httr::GET() uses
api_get <- function(url, ..., key = NULL, as = "text") {
if (!is.null(key))
key <- httr::add_headers("X-Dataverse-key", key)
r <- httr::GET(url, ..., key)
httr::stop_for_status(r, task = httr::content(r)$message)
httr::content(r, as = as, encoding = "UTF-8")
#' @importFrom checkmate assert_character assert_logical
api_get <- function(url, ..., key = NULL, as = "text", use_cache = as.logical(Sys.getenv("DATAVERSE_USE_CACHE", TRUE))) {
assert_character(url, any.missing = FALSE, len = 1L, null.ok = TRUE)
assert_character(key, any.missing = FALSE, len = 1L, null.ok = TRUE)
assert_character(as, any.missing = FALSE, len = 1L, null.ok = TRUE)
assert_logical(use_cache, any.missing = FALSE, len = 1L)
if (use_cache) {
get <- api_get_memoized
} else {
get <- api_get_impl
}
get(url, ..., key = key, as = as)
}

## cache implemented via memoization; memoized function defined in
## .onLoad()
api_get_impl <- function(url, ..., key = NULL, as = "text") {
if (!is.null(key))
key <- httr::add_headers("X-Dataverse-key", key)
r <- httr::GET(url, ..., key)
httr::stop_for_status(r, task = httr::content(r)$message)
httr::content(r, as = as, encoding = "UTF-8")
}

api_get_memoized <- NULL

# parse dataset response into list/dataframe
parse_dataset <- function(out) {
out <- jsonlite::fromJSON(out)$data
Expand Down
9 changes: 6 additions & 3 deletions man-roxygen/dots.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#' @param ... Additional arguments passed to an HTTP request function, such as
#' \code{\link[httr]{GET}}, \code{\link[httr]{POST}}, or
#' \code{\link[httr]{DELETE}}.
#' @param ... Additional arguments passed to an HTTP request function,
#' such as \code{\link[httr]{GET}}, \code{\link[httr]{POST}}, or
#' \code{\link[httr]{DELETE}}. By default, HTTP requests use
#' values cached from previous identical calls. Use
#' \code{use_cache=FALSE} (or `Sys.setenv(DATAVERSE_USE_CACHE =
#' FALSE)` if cached API calls are not desired.
8 changes: 5 additions & 3 deletions man/URLs.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/add_dataset_file.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/add_file.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/create_dataset.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/create_dataverse.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/dataset_atom.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/dataset_versions.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/dataverse_metadata.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/delete_dataset.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/delete_dataverse.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/delete_file.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/delete_sword_dataset.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/files.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/get_dataset.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/get_dataverse.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/get_facets.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/get_file_metadata.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/get_user_key.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions man/initiate_sword_dataset.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 27787ab

Please sign in to comment.