Skip to content

Commit

Permalink
Translate pmin()/pmax() to LEAST()/GREATEST()
Browse files Browse the repository at this point in the history
Except for SQLite (which uses MIN()/MAX()) and MS SQL (which errors)

Fixes #118.
  • Loading branch information
hadley committed Jan 10, 2019
1 parent 1a3fd7c commit 7667461
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 8 deletions.
4 changes: 4 additions & 0 deletions NEWS.md
@@ -1,5 +1,9 @@
# dbplyr (development version)

* Default translation for `pmin()` and `pmax()` becomes `LEAST()` and
`GREATEST()` (#118). SQLite instead uses `MIN()` and `MAX()`, and MS SQL
throws an error.

* Default translator gains translations for `paste()`, `paste0()`,
and the hyperbolic functions (these previously were only available for
ODBC based translations).
Expand Down
5 changes: 5 additions & 0 deletions R/db-odbc-mssql.R
Expand Up @@ -72,6 +72,11 @@
atan2 = sql_prefix("ATN2"),
ceil = sql_prefix("CEILING"),
ceiling = sql_prefix("CEILING"),

# https://dba.stackexchange.com/questions/187090
pmin = sql_not_supported("pmin()"),
pmax = sql_not_supported("pmax()"),

substr = function(x, start, stop) {
len <- stop - start + 1
sql_expr(SUBSTRING(!!x, !!start, !!len))
Expand Down
6 changes: 5 additions & 1 deletion R/db-sqlite.r
Expand Up @@ -24,7 +24,11 @@ sql_translate_env.SQLiteConnection <- function(con) {
},
na_if = sql_prefix("NULLIF", 2),
paste = sql_paste_infix(" ", "||", function(x) sql_expr(cast(!!x %as% text))),
paste0 = 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_prefix("MIN"),
pmax = sql_prefix("MAX"),

),
sql_translator(.parent = base_agg,
sd = sql_aggregate("stdev", "sd")
Expand Down
4 changes: 2 additions & 2 deletions R/translate-sql-base.r
Expand Up @@ -167,8 +167,8 @@ base_scalar <- sql_translator(
sql_expr(!!x %BETWEEN% !!left %AND% !!right)
},

pmin = sql_prefix("min"),
pmax = sql_prefix("max"),
pmin = sql_prefix("LEAST"),
pmax = sql_prefix("GREATEST"),

`%>%` = `%>%`,

Expand Down
9 changes: 9 additions & 0 deletions tests/testthat/test-translate-sqlite.R
Expand Up @@ -10,6 +10,15 @@ test_that("vectorised translations", {
expect_equal(trans(paste0(x, y)), sql("`x` || `y`"))
})

test_that("pmin and max become MIN and MAX", {
trans <- function(x) {
translate_sql(!!enquo(x), con = simulate_sqlite(), window = FALSE)
}

expect_equal(trans(pmin(x, y)), sql('MIN(`x`, `y`)'))
expect_equal(trans(pmax(x, y)), sql('MAX(`x`, `y`)'))
})

test_that("as.numeric()/as.double() get custom translation", {
mf <- dbplyr::memdb_frame(x = 1L)

Expand Down
11 changes: 6 additions & 5 deletions tests/testthat/test-translate.r
Expand Up @@ -53,11 +53,6 @@ test_that("all forms of if translated to case statement", {
expect_equal(translate_sql(if_else(x, 1L, 2L)), expected)
})

test_that("pmin and pmax become min and max", {
expect_equal(translate_sql(pmin(x, y)), sql('MIN("x", "y")'))
expect_equal(translate_sql(pmax(x, y)), sql('MAX("x", "y")'))
})

test_that("%in% translation parenthesises when needed", {
expect_equal(translate_sql(x %in% 1L), sql('"x" IN (1)'))
expect_equal(translate_sql(x %in% c(1L)), sql('"x" IN (1)'))
Expand Down Expand Up @@ -114,6 +109,12 @@ test_that("hypergeometric functions use manual calculation", {
expect_equal(translate_sql(coth(x)), sql('(EXP(2 * ("x")) + 1) / (EXP(2 * ("x")) - 1)'))
})


test_that("pmin and max use GREATEST and LEAST", {
expect_equal(translate_sql(pmin(x, y)), sql('LEAST("x", "y")'))
expect_equal(translate_sql(pmax(x, y)), sql('GREATEST("x", "y")'))
})

test_that("round uses integer digits", {
expect_equal(translate_sql(round(10.1)), sql("ROUND(10.1, 0)"))
expect_equal(translate_sql(round(10.1, digits = 1)), sql("ROUND(10.1, 1)"))
Expand Down

0 comments on commit 7667461

Please sign in to comment.