Skip to content

Commit

Permalink
Two engines: glue and jinjar (#21)
Browse files Browse the repository at this point in the history
* glue and jinjar both work

* update README
  • Loading branch information
daranzolin authored Jul 27, 2024
1 parent 9c4134c commit bbf937f
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 85 deletions.
11 changes: 10 additions & 1 deletion R/source_sql_to_dataframe.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ source_sql_to_dataframe <- function(path, params = NULL) {
rlang::eval_bare(rlang::parse_expr(connection_call))
on.exit(DBI::dbDisconnect(con))
query <- readr::read_file(path)
if (!is.null(params)) {
template_engine <- sqltargets_option_get("sqltargets.template_engine")
if (template_engine == "jinjar") {
query <- jinjar::render(
query,
params = params,
Expand All @@ -18,6 +19,14 @@ source_sql_to_dataframe <- function(path, params = NULL) {
comment_close = sqltargets_option_get("sqltargets.jinja_comment_close"),
)
)
} else {
query <- glue::glue_sql(
query,
.con = con,
.open = sqltargets_option_get("sqltargets.glue_sql_opening_delimiter"),
.close = sqltargets_option_get("sqltargets.glue_sql_closing_delimiter"),
.envir = params
)
}
out <- DBI::dbGetQuery(con, query)
msg <- glue::glue("{basename(path)} executed:\n Rows: {nrow(out)}\n Columns: {ncol(out)}")
Expand Down
13 changes: 12 additions & 1 deletion R/sqltargets-option.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@
#'
#' @details
#'
#' ## Available Options
#' Available Options
#'
#' - `"sqltargets.template_engine"` - Either 'glue' or 'jinjar'. Determines how the query file should be parsed`.
#'
#' - `"sqltargets.glue_sql_opening_delimiter"` - character. Length 1. The opening delimiter passed to `glue::glue_sql()`.
#'
#' - `"sqltargets.glue_sql_closing_delimiter"` - character. Length 1. The closing delimiter passed to `glue::glue_sql()`.
#'
#' - `"sqltargets.jinja_block_open"` - character. Length 1. The opening delimiter passed to `jinjar::jinjar_config()`.
#'
#' - `"sqltargets.jinja_block_close"` - character. Length 1. The closing delimiter passed to `jinjar::jinjar_config()`.
#'
#' - `"sqltargets.jinja_variable_open"` - character. Length 1. The closing delimiter passed to `jinjar::jinjar_config()`.
#'
#' - `"sqltargets.jinja_variable_close"` - character. Length 1. The closing delimiter passed to `jinjar::jinjar_config()`.
#'
#' - `"sqltargets.jinja_comment_open"` - character. Length 1. The closing delimiter passed to `jinjar::jinjar_config()`.
#'
#' - `"sqltargets.jinja_comment_close"` - character. Length 1. The closing delimiter passed to `jinjar::jinjar_config()`.
#' @rdname sqltargets-options
#' @export
Expand Down
3 changes: 3 additions & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ sqltargets_env <- function() {

.onAttach <- function(lib, pkg) {
jinjar_defaults <- jinjar::default_config()
sqltargets.env$sqltargets.template_engine <- "glue"
sqltargets.env$sqltargets.glue_sql_opening_delimiter <- "{"
sqltargets.env$sqltargets.glue_sql_closing_delimiter <- "}"
sqltargets.env$sqltargets.jinja_block_open <- jinjar_defaults$block_open
sqltargets.env$sqltargets.jinja_block_close <- jinjar_defaults$block_close
sqltargets.env$sqltargets.jinja_comment_open <- jinjar_defaults$comment_open
Expand Down
89 changes: 50 additions & 39 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,13 @@ You can install the development version of sqltargets with:
remotes::install_github("daranzolin/sqltargets)
```
## Example
```{r example}
library(targets)
library(sqltargets)
tar_dir({ #
# Unparameterized SQL query:
lines <- c(
"-- !preview conn=DBI::dbConnect(RSQLite::SQLite())",
"select 1 AS my_col",
""
)
writeLines(lines, "query.sql")
# Include the query in a pipeline as follows.
tar_script({
library(sqltargets)
list(
tar_sql(query, path = "query.sql")
)
}, ask = FALSE)
})
```
## Specifying dependencies
## Dependencies
Use `tar_load` or `targets::tar_load` within a SQL comment to indicate query
dependencies. Check the dependencies of any query with `tar_sql_deps`.
```{r}
library(sqltargets)
lines <- c(
"-- !preview conn=DBI::dbConnect(RSQLite::SQLite())",
"-- targets::tar_load(data1)",
Expand All @@ -82,36 +59,70 @@ lines <- c(
tar_sql_deps(query)
```
## Passing parameters
## Parameters
Pass parameters (presumably from another object in your targets project) from a named list with
'glue' syntax: `{param}`.
You can pass parameters (presumably from another object in your targets project) to `tar_sql()` using one of two 'template engines': [glue](https://github.com/tidyverse/glue) or 'Jinja' (courtesy of [the 'jinjar' package.)](https://github.com/davidchall/jinjar)
Set the 'template engine' with `sqltargets_option_set("sqltargets.template_engine", "jinjar")`. ('glue' is the default.)
With glue:
`query.sql`
```sql
-- !preview conn=DBI::dbConnect(RSQLite::SQLite())
-- tar_load(query_params)
-- tar_load(params)
select id
from table
where age > {age_threshold}
```
`_targets.R`
```{r eval = FALSE}
tar_script({
library(targets)
library(sqltargets)
list(
tar_target(query_params, list(age_threshold = 30)),
tar_sql(report, path = "query.sql", query_params = query_params)
)
}, ask = FALSE)
tar_visnetwork()
library(targets)
library(sqltargets)
list(
tar_target(params, list(age_threshold = 30)),
tar_sql(report, path = "query.sql", params = params)
)
```
![](inst/tar_visnetwork.png)
With 'Jinja':
`query.sql`
```sql
-- !preview conn=DBI::dbConnect(RSQLite::SQLite())
-- tar_load(payment_methods)
select
order_id,
{% for payment_method in params.payment_methods %}
sum(case when payment_method = '{{payment_method}}' then amount end) as {{payment_method}}_amount
{% if not loop.is_last %},{% endif %}
{% endfor %}
from payments
group by 1
```
`_targets.R`
```{r eval = FALSE}
library(targets)
library(sqltargets)
sqltargets_option_set("sqltargets.template_engine", "jinjar")
list(
tar_target(payment_methods, list(payment_methods = c("bank_transfer", "credit_card", "gift_card"))),
tar_sql(report, path = "query.sql", params = payment_methods)
)
```
Note that `loop.is_last` differs from typical Jinja (`loop.last`). Refer to [this 'jinjar' vignette](https://davidchall.github.io/jinjar/articles/template-syntax.html) for other syntactical differences.
## Code of Conduct
Please note that the sqltargets project is released with a [Contributor Code of Conduct](https://contributor-covenant.org/version/2/1/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms.
Expand Down
98 changes: 58 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,38 +40,14 @@ You can install the development version of sqltargets with:
remotes::install_github("daranzolin/sqltargets)
```
## Example
``` r
library(targets)
#> Warning: package 'targets' was built under R version 4.2.2
library(sqltargets)
tar_dir({ #
# Unparameterized SQL query:
lines <- c(
"-- !preview conn=DBI::dbConnect(RSQLite::SQLite())",
"select 1 AS my_col",
""
)
writeLines(lines, "query.sql")
# Include the query in a pipeline as follows.
tar_script({
library(sqltargets)
list(
tar_sql(query, path = "query.sql")
)
}, ask = FALSE)
})
```
## Specifying dependencies
## Dependencies
Use `tar_load` or `targets::tar_load` within a SQL comment to indicate
query dependencies. Check the dependencies of any query with
`tar_sql_deps`.
``` r
library(sqltargets)
lines <- c(
"-- !preview conn=DBI::dbConnect(RSQLite::SQLite())",
"-- targets::tar_load(data1)",
Expand All @@ -85,36 +61,78 @@ lines <- c(
#> [1] "data1" "data2"
```
## Passing parameters
## Parameters
You can pass parameters (presumably from another object in your targets
project) to `tar_sql()` using one of two ‘template engines’:
[glue](https://github.com/tidyverse/glue) or ‘Jinja’ (courtesy of [the
‘jinjar’ package.)](https://github.com/davidchall/jinjar)
Pass parameters (presumably from another object in your targets project)
from a named list with ‘glue’ syntax: `{param}`.
Set the ‘template engine’ with
`sqltargets_option_set("sqltargets.template_engine", "jinjar")`. (‘glue’
is the default.)
With glue:
`query.sql`
``` sql
-- !preview conn=DBI::dbConnect(RSQLite::SQLite())
-- tar_load(query_params)
-- tar_load(params)
select id
from table
where age > {age_threshold}
```
`_targets.R`
``` r
tar_script({
library(targets)
library(sqltargets)
list(
tar_target(query_params, list(age_threshold = 30)),
tar_sql(report, path = "query.sql", query_params = query_params)
)
}, ask = FALSE)
tar_visnetwork()
library(targets)
library(sqltargets)
list(
tar_target(params, list(age_threshold = 30)),
tar_sql(report, path = "query.sql", params = params)
)
```
![](inst/tar_visnetwork.png)
With ‘Jinja’:
`query.sql`
``` sql
-- !preview conn=DBI::dbConnect(RSQLite::SQLite())
-- tar_load(payment_methods)
select
order_id,
{% for payment_method in params.payment_methods %}
sum(case when payment_method = '{{payment_method}}' then amount end) as {{payment_method}}_amount
{% if not loop.is_last %},{% endif %}
{% endfor %}
from payments
group by 1
```
`_targets.R`
``` r
library(targets)
library(sqltargets)
sqltargets_option_set("sqltargets.template_engine", "jinjar")
list(
tar_target(payment_methods, list(payment_methods = c("bank_transfer", "credit_card", "gift_card"))),
tar_sql(report, path = "query.sql", params = payment_methods)
)
```
Note that `loop.is_last` differs from typical Jinja (`loop.last`). Refer
to [this ‘jinjar’
vignette](https://davidchall.github.io/jinjar/articles/template-syntax.html)
for other syntactical differences.
## Code of Conduct
Please note that the sqltargets project is released with a [Contributor
Expand Down
13 changes: 12 additions & 1 deletion man/sqltargets-options.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 28 additions & 1 deletion tests/testthat/test-tar-sql.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,32 @@ targets::tar_test("tar_sql() works", {
expect_equal(sort(targets::tar_progress()$name), sort(c("data", "report", "query.sql")))
})

targets::tar_test("tar_sql() for Jinja queries 1", {
targets::tar_test("tar_sql() with glue engine", {
lines <- c(
"-- !preview conn=DBI::dbConnect(RSQLite::SQLite())",
"-- tar_load(query_params)",
"select {val} as {col_name}",
""
)
writeLines(lines, "query.sql")
targets::tar_script({
library(sqltargets)
sqltargets_option_set("sqltargets.template_engine", "glue")
list(
targets::tar_target(params, list(val = 3, col_name = "column1")),
tar_sql(
report,
path = "query.sql",
params = params
)
)
})
suppressMessages(targets::tar_make(callr_function = NULL))
out <- targets::tar_read(report)
expect_equal(out, data.frame(column1 = 3))
})

targets::tar_test("tar_sql() with jinjar engine", {
lines <- c(
"-- !preview conn=DBI::dbConnect(RSQLite::SQLite())",
"-- tar_load(params)",
Expand All @@ -45,6 +70,7 @@ targets::tar_test("tar_sql() for Jinja queries 1", {
writeLines(lines, "query.sql")
targets::tar_script({
library(sqltargets)
sqltargets_option_set("sqltargets.template_engine", "jinjar")
list(
targets::tar_target(params, list(val = 3, col_name = "column1")),
tar_sql(
Expand Down Expand Up @@ -73,6 +99,7 @@ targets::tar_test("tar_sql() for Jinja for loop", {
writeLines(lines, "query.sql")
targets::tar_script({
library(sqltargets)
sqltargets_option_set("sqltargets.template_engine", "jinjar")
list(
targets::tar_target(params, list(payment_methods = c("bank_transfer", "credit_card", "gift_card"))),
tar_sql(
Expand Down
Loading

0 comments on commit bbf937f

Please sign in to comment.