forked from tidyverse/dbplyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsql-build.R
97 lines (84 loc) · 3.02 KB
/
sql-build.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#' Build and render SQL from a sequence of lazy operations
#'
#' `sql_build()` creates a `select_query` S3 object, that is rendered
#' to a SQL string by `sql_render()`. The output from `sql_build()` is
#' designed to be easy to test, as it's database agnostic, and has
#' a hierarchical structure. Outside of testing, however, you should
#' always call `sql_render()`.
#'
#' `sql_build()` is generic over the lazy operations, \link{lazy_ops},
#' and generates an S3 object that represents the query. `sql_render()`
#' takes a query object and then calls a function that is generic
#' over the database. For example, `sql_build.op_mutate()` generates
#' a `select_query`, and `sql_render.select_query()` calls
#' `sql_select()`, which has different methods for different databases.
#' The default methods should generate ANSI 92 SQL where possible, so you
#' backends only need to override the methods if the backend is not ANSI
#' compliant.
#'
#' @export
#' @keywords internal
#' @param op A sequence of lazy operations
#' @param con A database connection. The default `NULL` uses a set of
#' rules that should be very similar to ANSI 92, and allows for testing
#' without an active database connection.
#' @param ... Other arguments passed on to the methods. Not currently used.
sql_build <- function(op, con = NULL, ...) {
UseMethod("sql_build")
}
#' @export
sql_build.tbl_lazy <- function(op, con = op$src$con, ...) {
# only used for testing
qry <- sql_build(op$ops, con = con, ...)
sql_optimise(qry, con = con, ...)
}
#' @export
sql_build.ident <- function(op, con = NULL, ...) {
op
}
# Render ------------------------------------------------------------------
#' @export
#' @rdname sql_build
#' @param bare_identifier_ok Is it ok to return a bare table identifier.
#' Set to `TRUE` when generating queries to be nested within other
#' queries where a bare table name is ok.
sql_render <- function(query, con = NULL, ..., bare_identifier_ok = FALSE) {
UseMethod("sql_render")
}
#' @export
sql_render.tbl_lazy <- function(query, con = query$src$con, ..., bare_identifier_ok = FALSE) {
sql_render(query$ops, con = con, ..., bare_identifier_ok = bare_identifier_ok)
}
#' @export
sql_render.op <- function(query, con = NULL, ..., bare_identifier_ok = FALSE) {
qry <- sql_build(query, con = con, ...)
qry <- sql_optimise(qry, con = con, ...)
sql_render(qry, con = con, ..., bare_identifier_ok = bare_identifier_ok)
}
#' @export
sql_render.sql <- function(query, con = NULL, ..., bare_identifier_ok = FALSE) {
query
}
#' @export
sql_render.ident <- function(query, con = NULL, ..., bare_identifier_ok = FALSE) {
if (bare_identifier_ok) {
query
} else {
sql_select(con, sql("*"), query)
}
}
# Optimise ----------------------------------------------------------------
#' @export
#' @rdname sql_build
sql_optimise <- function(x, con = NULL, ...) {
UseMethod("sql_optimise")
}
#' @export
sql_optimise.sql <- function(x, con = NULL, ...) {
# Can't optimise raw SQL
x
}
#' @export
sql_optimise.ident <- function(x, con = NULL, ...) {
x
}