Возможно, вас смущает то, что функции dplyr tbl
и filter
фактически не отправляют какой-либо код в базу данных для выполнения.Когда вы запускаете
tbl(con, "table1") %>% filter(col1 > 12)
, возвращается объект tbl_dbi, содержащий SQL-запрос.Когда вы в интерактивном режиме запускаете эту строку кода в R, возвращенный объект tbl_dbi передается в функцию print
.Чтобы распечатать tbl_dbi, запрос должен быть выполнен в базе данных.Вы можете убедиться в этом, сохранив вывод в переменную.
q <- tbl(con, "table1") %>% filter(col1 > 12)
class(q)
В двух приведенных выше строках ничего не было отправлено в базу данных.Функция tbl
вернула объект tbl_dbi и фильтр изменил этот объект tbl_dbi.Наконец, результат был сохранен в переменную q
.Когда мы печатаем q
, тогда SQL отправляется в базу данных.Поэтому функции tbl
не нужно знать о каких-либо других функциях dplyr, которые вызываются после нее (например, filter
в этом случае).Он ведет себя одинаково, несмотря ни на что.Он всегда возвращает объект tbl_dbi.
Теперь, как dbplyr создает более сложные запросы из более простых, мне неизвестно.
Вот код, который реализует ваш пример.
library(dplyr)
shoppingList <- function(x){
stopifnot(is.character(x))
class(x) <- c("first", "shoppingList", class(x))
x
}
item <- function(x, y){
if("first" %in% class(x)){
out <- paste(x, y)
} else {
out <- paste0(x, " and ", y)
}
class(out) <- c("shoppingList", class(out))
out
}
print.shoppingList <- function(x){
# code that only runs when we print an object of class shoppingList
if("first" %in% class(x)) x <- paste(x, "nothing")
print(paste0("***", x, "***"))
}
shoppingList("I need to get")
#> [1] "***I need to get nothing***"
shoppingList("I need to get") %>% item("apples") %>% item("oranges")
#> [1] "***I need to get apples and oranges***"
Но как print
узнает, как отправить SQL в базу данных?Мой (упрощенно) концептуальный ответ заключается в том, что print
- это универсальная функция, которая будет вести себя по-разному в зависимости от класса переданного объекта. На самом деле существует множество print
функций.В приведенном выше примере я создал специальную функцию печати для объектов класса shoppingList .Вы можете представить себе специальную функцию print.tbl_dbi
, которая знает, как обрабатывать объекты tbl_dbi, отправляя запрос, который они содержат, в базу данных, к которой они подключаются, и затем печатая результат.Я думаю, что фактическая реализация более сложна, но, надеюсь, это даст некоторую интуицию.