Как позволить функции, определенной в глобальной среде, обращаться к переменным, определенным в среде ее вызывающей функции?

connect_dw <- function() {
  DBI::dbConnect(RSQLite::SQLite(), ":memory:")
}

fetch_sql_res <- function(key, ...) {
  query_list <- list(...)
  query_sql_res <- function(.query_list = query_list, .db_connect_f = connect_dw) {
    con <- .db_connect_f()
    res <- purrr::map(.query_list, glue::glue_sql, .con = con ) %>%
      purrr::map(purrr::partial(DBI::dbGetQuery, conn = con))
    DBI::dbDisconnect(con)
    res
  }

 ## if key exists in redis cache, fetch it from redis.
 ## If not, call the function to query database

  query_sql_res()

}

#' testing
#' @serializer unboxedJSON
#' @get /test_db
test_db <- function() {
  userid <- 10

  fetch_sql_res(df = "SELECT {userid}")
}

Сообщение об ошибке:

 Error in eval(parse(text = text, keep.source = FALSE), envir) : 
  object 'userid' not found

Я хочу создать функцию, которая может быть использована внутри функции (которая используется для создания веб-API с сантехником).

Функция используется для получения результата sql. Для построения запроса sql нужна некоторая переменная.

Приведенный выше код не работает. Кажется, проблема в окружающей среде.

1 ответ

Решение

Все функции R имеют лексическую область, что означает, что они наследуют переменные от того, где функция определена, а не от того, где она вызывается. Вы не можете изменить это поведение по умолчанию, потому что это сломало бы много вещей. Поэтому вам просто нужно быть осторожным с указанием правильной среды, когда вы выполняете вызовы функций, которые нуждаются в разных средах.

В этом случае проблемы, кажется, с glue::glue_sql не в состоянии найти переменную. Эта функция имеет .envir= параметр, который говорит ему, где искать переменные. Вам просто нужно явно передать вызывающую среду этой функции. Например

fetch_sql_res <- function(key, ...) {
  query_list <- list(...)
  calling_env <- parent.frame()
  query_sql_res <- function(.query_list = query_list, .db_connect_f = connect_dw) {
    con <- .db_connect_f()
    res <- purrr::map(.query_list, glue::glue_sql, .con = con, .envir=calling_env ) %>%
      purrr::map(purrr::partial(DBI::dbGetQuery, conn = con))
    DBI::dbDisconnect(con)
    res
  }
  query_sql_res()
}

Это не решение "общего назначения", но та же основная идея применима и в других местах. Вам нужно явно обратиться к вызывающей среде, когда вам это нужно.

Другие вопросы по тегам