Guide for adding SQL function translations to dbplyr backends. Use when implementing new database-specific R-to-SQL translations for functions like string manipulation, date/time, aggregates, or window functions.
Use this skill when adding new SQL function translations for a specific database backend.
This skill guides you through adding SQL translations to dbplyr. SQL translations convert R functions to their SQL equivalents for different database backends.
Before implementing any SQL translation, you MUST research the SQL syntax and behavior using the sql-research skill. See that skill for the complete research workflow.
Quick summary:
research/{dialect}-{function}.mdSQL translations are defined in backend-specific files:
R/backend-sqlite.R - SQLiteR/backend-postgres.R - PostgreSQLR/backend-mysql.R - MySQLR/backend-mssql.R - MS SQL ServerTranslations are added to the sql_translation() method for the connection class. This method returns a sql_variant() with three components:
Scalar translations (for mutate/filter):
sql_translator(.parent = base_scalar,
# Simple function name mapping
log10 = function(x) sql_expr(log(!!x)),
# Function with different arguments
round = function(x, digits = 0L) {
digits <- as.integer(digits)
sql_expr(round(((!!x)) %::% numeric, !!digits))
},
# Infix operators
paste0 = sql_paste(""),
# Complex logic
grepl = function(pattern, x, ignore.case = FALSE) {
if (ignore.case) {
sql_expr(((!!x)) %~*% ((!!pattern)))
} else {
sql_expr(((!!x)) %~% ((!!pattern)))
}
}
)
Aggregate translations (for summarise):
sql_translator(.parent = base_agg,
sd = sql_aggregate("STDEV", "sd"),
median = sql_aggregate("MEDIAN"),
quantile = sql_not_supported("quantile")
)
Window translations (for mutate with groups):
sql_translator(.parent = base_win,
sd = win_aggregate("STDEV"),
median = win_absent("median"),
quantile = sql_not_supported("quantile")
)
Common translation patterns:
sql_expr() - Build SQL expressions with !! for interpolationsql_cast(type) - Type casting (e.g., sql_cast("REAL"))sql_aggregate(sql_name, r_name) - Simple aggregatessql_paste(sep) - String concatenationsql_not_supported(name) - Mark unsupported functionswin_aggregate(sql_name) - Window aggregateswin_absent(name) - Window functions not supportedInteractive testing:
Rscript -e "devtools::load_all(); library(dplyr, warn.conflicts = FALSE);
translate_sql(your_function(x), con = simulate_yourdb())"
Write tests:
R/{name}.R go in tests/testthat/test-{name}.RExample test:
test_that("backend_name translates function_name correctly", {
lf <- lazy_frame(x = 1, con = simulate_backend())
expect_snapshot(
lf |> mutate(y = your_function(x))
)
})
Update backend documentation:
@description section in the backend file (e.g., R/backend-postgres.R)@examples if helpfulExample:
#' Backend: PostgreSQL
#'
#' @description
#' See `vignette("translation-function")` and `vignette("translation-verb")` for
#' details of overall translation technology. Key differences for this backend
#' are:
#'
#' * Many stringr functions
#' * lubridate date-time extraction functions
#' * Your new translation
# Format code
air format .
# Run relevant tests
Rscript -e "devtools::test(filter = 'backend-name', reporter = 'llm')"
# Check documentation
Rscript -e "devtools::document()"
Parent translators:
base_scalar - Common scalar functions (math, string, logical)base_agg - Common aggregates (sum, mean, min, max)base_win - Common window functionsSQL expression building:
sql_expr() to build SQL!! to interpolate R variables%as% for AS, %::% for ::, etc.Argument handling:
check_bool(), check_unsupported_arg()as.integer())See also:
vignette("translation-function") - Function translation overviewvignette("new-backend") - Creating new backendsBefore completing a SQL translation:
research/{dialect}-{function}.mdsql_translator() sectionair format .Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer