diff --git a/NAMESPACE b/NAMESPACE index 55894e812..8135c9aa2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -466,6 +466,7 @@ export(lahman_mysql) export(lahman_postgres) export(lahman_sqlite) export(lahman_srcs) +export(last_sql) export(lazy_base_query) export(lazy_frame) export(lazy_multi_join_query) diff --git a/NEWS.md b/NEWS.md index b940b903e..d14df0a10 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # dbplyr (development version) +* New `last_sql()` retrieves the most recent SQL query generated by dbplyr, which is useful for debugging (#1471). * Custom translations of functions starting with `.` work (@MichaelChirico, #1529). * SQL Server 2025 (version 17.0) now supports stringr regex functions: `str_detect()`, `str_starts()`, `str_ends()`, `str_replace()`, `str_replace_all()`, `str_remove()`, `str_remove_all()`, `str_extract()`, and `str_count()`. Fixed pattern versions of `str_detect()`, `str_starts()`, and `str_ends()` work on all SQL Server versions (#1671). * MS Access now correctly generates SQL for multiple joins by adding required parentheses (#1576). diff --git a/R/db.R b/R/db.R index be7065e44..753ab1ed2 100644 --- a/R/db.R +++ b/R/db.R @@ -49,17 +49,19 @@ db_sql_render <- function(con, sql, ..., cte = FALSE, sql_options = NULL) { with = I("db_sql_render(sql_options = sql_options(cte = TRUE))") ) sql_options <- sql_options %||% sql_options(cte = TRUE) - out <- db_sql_render(con, sql, ..., sql_options = sql_options) - return(out) } - if (is.null(sql_options)) { - sql_options <- sql_options() + sql_options <- sql_options %||% sql_options() - out <- db_sql_render(con, sql, ..., sql_options = sql_options) - return(out) - } + out <- db_sql_render_dispatch(con, sql, ..., sql_options = sql_options) + the$last_sql <- out + return(out) + + # Unusued declaration for roxygen2 + UseMethod("db_sql_render") +} +db_sql_render_dispatch <- function(con, sql, ..., sql_options) { UseMethod("db_sql_render") } #' @export diff --git a/R/remote.R b/R/remote.R index 4713b3f47..3cf0ab990 100644 --- a/R/remote.R +++ b/R/remote.R @@ -106,3 +106,21 @@ remote_query <- function(x, cte = FALSE, sql_options = NULL) { remote_query_plan <- function(x, ...) { dbplyr_explain(remote_con(x), db_sql_render(remote_con(x), x$lazy_query), ...) } + +#' Retrieve the last SQL query generated +#' +#' This is a helper function that retrieves the most recent SQL query generated +#' by dbplyr, which can be useful for debugging. +#' +#' @return A SQL string, or `NULL` if no query has been generated yet. +#' @export +#' @examples +#' library(dplyr, warn.conflicts = FALSE) +#' +#' df <- lazy_frame(x = 1:3) +#' df |> filter(x > 1) +#' +#' last_sql() +last_sql <- function() { + the$last_sql +} diff --git a/_pkgdown.yml b/_pkgdown.yml index 6ace857d0..3b6c1ad9b 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -28,6 +28,7 @@ reference: - copy_inline - pull.tbl_sql - show_query + - last_sql - .sql - subtitle: Verbs that affect rows diff --git a/man/last_sql.Rd b/man/last_sql.Rd new file mode 100644 index 000000000..c1df8d800 --- /dev/null +++ b/man/last_sql.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/remote.R +\name{last_sql} +\alias{last_sql} +\title{Retrieve the last SQL query generated} +\usage{ +last_sql() +} +\value{ +A SQL string, or \code{NULL} if no query has been generated yet. +} +\description{ +This is a helper function that retrieves the most recent SQL query generated +by dbplyr, which can be useful for debugging. +} +\examples{ +library(dplyr, warn.conflicts = FALSE) + +df <- lazy_frame(x = 1:3) +df |> filter(x > 1) + +last_sql() +} diff --git a/tests/testthat/test-remote.R b/tests/testthat/test-remote.R index 1cc4e1c2a..2d8df4122 100644 --- a/tests/testthat/test-remote.R +++ b/tests/testthat/test-remote.R @@ -74,3 +74,13 @@ test_that("can retrieve query, src and con metadata", { expect_s3_class(remote_query(mf), "sql") expect_type(remote_query_plan(mf), "character") }) + +test_that("last_sql() retrieves the most recent query", { + lf <- lazy_frame(x = 1:3, y = c("a", "b", "c")) + + lf |> filter(x > 1) |> show_query() + expect_match(last_sql(), "WHERE") + + lf |> mutate(z = x + 1) |> show_query() + expect_match(last_sql(), "\\+ 1") +})