diff --git a/R/tbl-sql.R b/R/tbl-sql.R index ef27ac25b..b32ef97f4 100644 --- a/R/tbl-sql.R +++ b/R/tbl-sql.R @@ -21,18 +21,32 @@ tbl_sql <- function(subclass, check_from = deprecated()) { # Can't use check_dots_used(), #1429 check_character(vars, allow_null = TRUE) - if (lifecycle::is_present(check_from)) { lifecycle::deprecate_warn("2.5.0", "tbl_sql(check_from)") } - from <- as_table_source(from, con = src$con) - vars <- vars %||% dbplyr_query_fields(src$con, from) + is_suspicious <- is_bare_string(from) && grepl(".", from, fixed = TRUE) + source <- as_table_source(from, con = src$con) + + withCallingHandlers( + vars <- vars %||% dbplyr_query_fields(src$con, source), + error = function(err) { + if (!is_suspicious) return() + + cli::cli_abort( + c( + "Failed to find table {source}.", + i = "Did you mean {.code from = I({.str {from}})}?" + ), + parent = err + ) + } + ) dplyr::make_tbl( c(subclass, "sql", "lazy"), src = src, - lazy_query = lazy_query_remote(from, vars) + lazy_query = lazy_query_remote(source, vars) ) } diff --git a/tests/testthat/_snaps/tbl-sql.md b/tests/testthat/_snaps/tbl-sql.md index d07493dc3..ada327233 100644 --- a/tests/testthat/_snaps/tbl-sql.md +++ b/tests/testthat/_snaps/tbl-sql.md @@ -11,6 +11,20 @@ 2 2 2 3 3 1 +# useful error if missing I() + + Code + tbl(src_memdb(), "foo.bar") + Condition + Error in `tbl_sql()`: + ! Failed to find table `foo.bar`. + i Did you mean `from = I("foo.bar")`? + Caused by error in `db_query_fields.DBIConnection()`: + ! Can't query fields. + i Using SQL: SELECT * FROM `foo.bar` AS `q05` WHERE (0 = 1) + Caused by error: + ! no such table: foo.bar + # check_from is deprecated Code diff --git a/tests/testthat/test-tbl-sql.R b/tests/testthat/test-tbl-sql.R index 01c8bd948..407b6c101 100644 --- a/tests/testthat/test-tbl-sql.R +++ b/tests/testthat/test-tbl-sql.R @@ -54,6 +54,13 @@ test_that("can distinguish 'schema.table' from 'schema'.'table'", { expect_equal(as.character(tbl_vars(df)), c("a", "b", "c")) }) +test_that("useful error if missing I()", { + expect_snapshot( + tbl(src_memdb(), "foo.bar"), + error = TRUE + ) +}) + test_that("check_from is deprecated", { con <- local_sqlite_connection() DBI::dbExecute(con, "CREATE TABLE x (y)")