From 717ae8a5010f865b24844d2fd1e24f6b97e521cf Mon Sep 17 00:00:00 2001 From: IoannaNika Date: Thu, 12 Dec 2024 10:07:44 +0100 Subject: [PATCH 1/3] fix/add clock functions and corresponding tests --- R/backend-dbplyr__duckdb_connection.R | 11 +++++++++++ .../testthat/test-backend-dbplyr__duckdb_connection.R | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/R/backend-dbplyr__duckdb_connection.R b/R/backend-dbplyr__duckdb_connection.R index f0a060712..64616b173 100644 --- a/R/backend-dbplyr__duckdb_connection.R +++ b/R/backend-dbplyr__duckdb_connection.R @@ -307,6 +307,17 @@ sql_translation.duckdb_connection <- function(con) { build_sql("DATEDIFF('day', ", !!start, ", " ,!!end, ")") }, + date_build = function(year, month = 1L, day = 1L, ..., invalid = NULL) { + dbplyr:::check_unsupported_arg(invalid, allow_null = TRUE) + rlang::check_dots_empty() + build_sql("MAKE_DATE(CAST(", year, " AS INTEGER), CAST(", month, " AS INTEGER), CAST(", day, " AS INTEGER))") + + }, + difftime = function(time1, time2, tz, units = "days") { + dbplyr:::check_unsupported_arg(tz) + dbplyr:::check_unsupported_arg(units, allowed = "days") + build_sql("DATEDIFF('day', ", !!time2, ", " ,!!time1, ")") + }, # stringr functions str_c = sql_paste(""), diff --git a/tests/testthat/test-backend-dbplyr__duckdb_connection.R b/tests/testthat/test-backend-dbplyr__duckdb_connection.R index 2bfb56af6..8ec55c64a 100644 --- a/tests/testthat/test-backend-dbplyr__duckdb_connection.R +++ b/tests/testthat/test-backend-dbplyr__duckdb_connection.R @@ -152,6 +152,10 @@ test_that("custom clock functions translated correctly", { precision = "day")), sql(r"{DATEDIFF('day', start, end)}")) + expect_equal(translate(difftime(time1 = "time1", time2 = "time2", units = "days")), sql(r"{DATEDIFF('day', time2, time1)}")) + expect_equal(translate(date_build(year = 2000, month = 08, day = 08)), sql(r"{MAKE_DATE(CAST(2000.0 AS INTEGER), CAST(8.0 AS INTEGER), CAST(8.0 AS INTEGER))}")) + expect_equal(translate(date_build(year = 2000)), sql(r"{MAKE_DATE(CAST(2000.0 AS INTEGER), CAST(1 AS INTEGER), CAST(1 AS INTEGER))}")) + test_data <- data.frame( person = 1L, date_1 = as.Date("2000-01-01"), @@ -193,6 +197,9 @@ test_that("custom clock functions translated correctly", { precision = "day", n = 5))) + expect_error(translate(date_build(year = 2000, month = 08, day = 08, invalid = "next-day"))) + expect_error(translate(difftime(time1, time2, units = "secs"))) + expect_error(translate(difftime(time1, time2, tz = Sys.timezone()))) }) # stringr functions From 403be02e76d1e845b642f3f61a24d6547942f377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 7 Sep 2025 14:52:24 +0200 Subject: [PATCH 2/3] Update tests/testthat/test-backend-dbplyr__duckdb_connection.R --- tests/testthat/test-backend-dbplyr__duckdb_connection.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-backend-dbplyr__duckdb_connection.R b/tests/testthat/test-backend-dbplyr__duckdb_connection.R index 8ec55c64a..8516911b7 100644 --- a/tests/testthat/test-backend-dbplyr__duckdb_connection.R +++ b/tests/testthat/test-backend-dbplyr__duckdb_connection.R @@ -153,7 +153,7 @@ test_that("custom clock functions translated correctly", { sql(r"{DATEDIFF('day', start, end)}")) expect_equal(translate(difftime(time1 = "time1", time2 = "time2", units = "days")), sql(r"{DATEDIFF('day', time2, time1)}")) - expect_equal(translate(date_build(year = 2000, month = 08, day = 08)), sql(r"{MAKE_DATE(CAST(2000.0 AS INTEGER), CAST(8.0 AS INTEGER), CAST(8.0 AS INTEGER))}")) + expect_equal(translate(date_build(year = 2000L, month = 8L, day = 8L)), sql(r"{MAKE_DATE(CAST(2000.0 AS INTEGER), CAST(8.0 AS INTEGER), CAST(8.0 AS INTEGER))}")) expect_equal(translate(date_build(year = 2000)), sql(r"{MAKE_DATE(CAST(2000.0 AS INTEGER), CAST(1 AS INTEGER), CAST(1 AS INTEGER))}")) test_data <- data.frame( From 69dbe638295070b0d16d253d5a7ac351c17812b9 Mon Sep 17 00:00:00 2001 From: IoannaNika Date: Wed, 15 Oct 2025 16:51:54 +0200 Subject: [PATCH 3/3] changes + updates from previous PR (date_build, difftime) --- R/backend-dbplyr__duckdb_connection.R | 11 ++-- R/check_unsupported_arg.R | 50 +++++++++++++++++++ ...b_src_function_table_system-6d8b1e5a.o.tmp | 0 .../test-backend-dbplyr__duckdb_connection.R | 6 +-- 4 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 R/check_unsupported_arg.R create mode 100644 src/duckdb/ub_src_function_table_system-6d8b1e5a.o.tmp diff --git a/R/backend-dbplyr__duckdb_connection.R b/R/backend-dbplyr__duckdb_connection.R index 64616b173..29226c2c2 100644 --- a/R/backend-dbplyr__duckdb_connection.R +++ b/R/backend-dbplyr__duckdb_connection.R @@ -308,15 +308,14 @@ sql_translation.duckdb_connection <- function(con) { }, date_build = function(year, month = 1L, day = 1L, ..., invalid = NULL) { - dbplyr:::check_unsupported_arg(invalid, allow_null = TRUE) + check_unsupported_arg(invalid, allow_null = TRUE) rlang::check_dots_empty() - build_sql("MAKE_DATE(CAST(", year, " AS INTEGER), CAST(", month, " AS INTEGER), CAST(", day, " AS INTEGER))") - + dbplyr::sql_expr(MAKE_DATE(!!year, !!month, !!day)) }, difftime = function(time1, time2, tz, units = "days") { - dbplyr:::check_unsupported_arg(tz) - dbplyr:::check_unsupported_arg(units, allowed = "days") - build_sql("DATEDIFF('day', ", !!time2, ", " ,!!time1, ")") + check_unsupported_arg(tz) + check_unsupported_arg(units, allowed = "days") + dbplyr::sql_expr(DATEDIFF("day", !!time2, !!time1)) }, # stringr functions diff --git a/R/check_unsupported_arg.R b/R/check_unsupported_arg.R new file mode 100644 index 000000000..5f3b4de52 --- /dev/null +++ b/R/check_unsupported_arg.R @@ -0,0 +1,50 @@ +#' Check for unsupported argument values +#' +#' The function checks whether a given argument is unsupported +#' It throws an error message if the argument is not among the allowed values. +#' Function is taken from dplyr. +#' +#' @param x The argument to check. +#' @param allowed A value or vector of values that are allowed for `x`. If `NULL`, no value is allowed. +#' @param allow_null Logical. If `TRUE`, allows `x` to be `NULL`. +#' @param backend Optional character string indicating the back-end. +#' @param arg The name of the argument being checked (automatically inferred via `rlang::caller_arg()`). +#' @param call The calling environment used for error reporting (automatically inferred via `rlang::caller_env()`). +#' +#' @noRd +check_unsupported_arg <- function (x, allowed = NULL, allow_null = FALSE, backend = NULL, + arg = caller_arg(x), call = caller_env()) +{ + if (rlang::is_missing(x)) { + return() + } + if (allow_null && rlang::is_null(x)) { + return() + } + if (identical(x, allowed)) { + return() + } + if (rlang::is_null(allowed)) { + msg <- "Argument {.arg {arg}} isn't supported" + } + else { + msg <- "{.code {arg} = {.val {x}}} isn't supported" + } + if (is.null(backend)) { + msg <- paste0(msg, " on database backends.") + } + else { + msg <- paste0(msg, " in {backend} translation.") + } + if (!rlang::is_null(allowed)) { + if (allow_null) { + allow_msg <- "It must be {.val {allowed}} or {.code NULL} instead." + } + else { + allow_msg <- "It must be {.val {allowed}} instead." + } + msg <- c(msg, i = allow_msg) + } + cli_abort(msg, call = call) +} + diff --git a/src/duckdb/ub_src_function_table_system-6d8b1e5a.o.tmp b/src/duckdb/ub_src_function_table_system-6d8b1e5a.o.tmp new file mode 100644 index 000000000..e69de29bb diff --git a/tests/testthat/test-backend-dbplyr__duckdb_connection.R b/tests/testthat/test-backend-dbplyr__duckdb_connection.R index 8516911b7..8c3a5b9b2 100644 --- a/tests/testthat/test-backend-dbplyr__duckdb_connection.R +++ b/tests/testthat/test-backend-dbplyr__duckdb_connection.R @@ -152,9 +152,9 @@ test_that("custom clock functions translated correctly", { precision = "day")), sql(r"{DATEDIFF('day', start, end)}")) - expect_equal(translate(difftime(time1 = "time1", time2 = "time2", units = "days")), sql(r"{DATEDIFF('day', time2, time1)}")) - expect_equal(translate(date_build(year = 2000L, month = 8L, day = 8L)), sql(r"{MAKE_DATE(CAST(2000.0 AS INTEGER), CAST(8.0 AS INTEGER), CAST(8.0 AS INTEGER))}")) - expect_equal(translate(date_build(year = 2000)), sql(r"{MAKE_DATE(CAST(2000.0 AS INTEGER), CAST(1 AS INTEGER), CAST(1 AS INTEGER))}")) + expect_equal(translate(difftime(time1 = "time1", time2 = "time2", units = "days")), sql(r"{DATEDIFF('day', 'time2', 'time1')}")) + expect_equal(translate(date_build(year = 2000L, month = 8L, day = 8L)), sql(r"{MAKE_DATE(2000, 8, 8)}")) + expect_equal(translate(date_build(year = 2000)), sql(r"{MAKE_DATE(2000.0, 1, 1)}")) test_data <- data.frame( person = 1L,