Как разрешить функции, определенной в глобальной среде, обращаться к переменным, определенным в среде вызывающей функции? - PullRequest
0 голосов
/ 05 сентября 2018
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 Ответ

0 голосов
/ 05 сентября 2018

Все функции 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()
}

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

...