Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
138 lines (124 sloc) 4.02 KB
#' Backend: SQLite
#'
#' @description
#' See `vignette("translate-function")` and `vignette("translate-verb")` for
#' details of overall translation technology. Key differences for this backend
#' are:
#'
#' * Uses non-standard `LOG()` function
#' * Date-time extraction functions from lubridate
#' * Custom median translation
#'
#' Use `simulate_sqlite()` with `lazy_frame()` to see simulated SQL without
#' converting to live access database.
#'
#' @name backend-sqlite
#' @aliases NULL
#' @examples
#' library(dplyr, warn.conflicts = FALSE)
#'
#' lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_sqlite())
#' lf %>% transmute(x = paste(c, " times"))
#' lf %>% transmute(x = log(b), y = log(b, base = 2))
NULL
#' @export
#' @rdname backend-sqlite
simulate_sqlite <- function() simulate_dbi("SQLiteConnection")
#' @export
dbplyr_edition.SQLiteConnection <- function(con) {
2L
}
#' @export
db_connection_describe.SQLiteConnection <- function(con) {
paste0("sqlite ", sqlite_version(), " [", con@dbname, "]")
}
#' @export
sql_query_explain.SQLiteConnection <- function(con, sql, ...) {
build_sql("EXPLAIN QUERY PLAN ", sql, con = con)
}
#' @export
sql_query_set_op.SQLiteConnection <- function(con, x, y, method, ..., all = FALSE) {
# SQLite does not allow parentheses
build_sql(
x,
"\n", sql(method), if (all) sql(" ALL"), "\n",
y,
con = con
)
}
sqlite_version <- function() {
numeric_version(RSQLite::rsqliteVersion()[[2]])
}
# SQL methods -------------------------------------------------------------
#' @export
sql_translation.SQLiteConnection <- function(con) {
sql_variant(
sql_translator(.parent = base_scalar,
as.numeric = sql_cast("REAL"),
as.double = sql_cast("REAL"),
log = function(x, base = exp(1)) {
if (base != exp(1)) {
sql_expr(log(!!x) / log(!!base))
} else {
sql_expr(log(!!x))
}
},
paste = sql_paste_infix(" ", "||", function(x) sql_expr(cast(!!x %as% text))),
paste0 = sql_paste_infix("", "||", function(x) sql_expr(cast(!!x %as% text))),
# https://www.sqlite.org/lang_corefunc.html#maxoreunc
pmin = sql_aggregate_n("MIN", "pmin"),
pmax = sql_aggregate_n("MAX", "pmax"),
# lubridate,
today = function() {
date <- function(x) {} # suppress R CMD check note
sql_expr(date("now"))
},
now = function() sql_expr(datetime("now")),
# https://modern-sql.com/feature/extract#proprietary-strftime
year = function(x) sql_expr(cast(strftime("%Y", !!x) %as% NUMERIC)),
month = function(x) sql_expr(cast(strftime("%m", !!x) %as% NUMERIC)),
mday = function(x) sql_expr(cast(strftime("%d", !!x) %as% NUMERIC)),
day = function(x) sql_expr(cast(strftime("%d", !!x) %as% NUMERIC)),
hour = function(x) sql_expr(cast(strftime("%H", !!x) %as% NUMERIC)),
minute = function(x) sql_expr(cast(strftime("%M", !!x) %as% NUMERIC)),
second = function(x) sql_expr(cast(strftime("%f", !!x) %as% REAL)),
yday = function(x) sql_expr(cast(strftime("%j", !!x) %as% NUMERIC)),
),
sql_translator(.parent = base_agg,
sd = sql_aggregate("STDEV", "sd"),
median = sql_aggregate("MEDIAN"),
),
if (sqlite_version() >= "3.25") {
sql_translator(.parent = base_win,
sd = win_aggregate("STDEV"),
median = win_absent("median")
)
} else {
base_no_win
}
)
}
#' @export
sql_escape_logical.SQLiteConnection <- function(con, x){
y <- as.character(as.integer(x))
y[is.na(x)] <- "NULL"
y
}
#' @export
sql_query_wrap.SQLiteConnection <- function(con, from, name = unique_subquery_name(), ...) {
if (is.ident(from)) {
setNames(from, name)
} else {
if (is.null(name)) {
build_sql("(", from, ")", con = con)
} else {
build_sql("(", from, ") AS ", ident(name), con = con)
}
}
}
#' @export
sql_expr_matches.SQLiteConnection <- function(con, x, y) {
# https://sqlite.org/lang_expr.html#isisnot
build_sql(x, " IS ", y, con = con)
}
globalVariables(c("datetime", "NUMERIC", "REAL"))
You can’t perform that action at this time.