├── .Rbuildignore ├── .covrignore ├── .gitattributes ├── .github ├── .gitignore ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ └── issue_template.md ├── SUPPORT.md ├── move.yml ├── odbc │ ├── odbc.ini │ └── odbcinst.ini └── workflows │ ├── R-CMD-check.yaml │ ├── mssql.yaml │ ├── pkgdown.yaml │ ├── postgres.yaml │ ├── pr-commands.yaml │ └── test-coverage.yaml ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── backend-.R ├── backend-access.R ├── backend-hana.R ├── backend-hive.R ├── backend-impala.R ├── backend-mssql.R ├── backend-mysql.R ├── backend-odbc.R ├── backend-oracle.R ├── backend-postgres-old.R ├── backend-postgres.R ├── backend-redshift.R ├── backend-snowflake.R ├── backend-spark-sql.R ├── backend-sqlite.R ├── backend-teradata.R ├── build-sql.R ├── data-cache.R ├── data-lahman.R ├── data-nycflights13.R ├── db-escape.R ├── db-io.R ├── db-sql.R ├── db.R ├── dbplyr.R ├── escape.R ├── explain.R ├── ident.R ├── import-standalone-obj-type.R ├── import-standalone-s3-register.R ├── import-standalone-types-check.R ├── join-by-compat.R ├── join-cols-compat.R ├── lazy-join-query.R ├── lazy-ops.R ├── lazy-query.R ├── lazy-select-query.R ├── lazy-set-op-query.R ├── memdb.R ├── optimise-utils.R ├── pillar.R ├── progress.R ├── query-join.R ├── query-select.R ├── query-semi-join.R ├── query-set-op.R ├── query.R ├── reexport.R ├── remote.R ├── rows.R ├── schema.R ├── simulate.R ├── sql-build.R ├── sql-clause.R ├── sql-expr.R ├── sql.R ├── src-sql.R ├── src_dbi.R ├── table-name.R ├── tbl-lazy.R ├── tbl-sql.R ├── test-frame.R ├── testthat.R ├── tidyeval-across.R ├── tidyeval.R ├── translate-sql-conditional.R ├── translate-sql-cut.R ├── translate-sql-helpers.R ├── translate-sql-paste.R ├── translate-sql-quantile.R ├── translate-sql-string.R ├── translate-sql-window.R ├── translate-sql.R ├── utils-check.R ├── utils-format.R ├── utils.R ├── verb-arrange.R ├── verb-compute.R ├── verb-copy-to.R ├── verb-count.R ├── verb-distinct.R ├── verb-do-query.R ├── verb-do.R ├── verb-expand.R ├── verb-fill.R ├── verb-filter.R ├── verb-group_by.R ├── verb-head.R ├── verb-joins.R ├── verb-mutate.R ├── verb-pivot-longer.R ├── verb-pivot-wider.R ├── verb-pull.R ├── verb-select.R ├── verb-set-ops.R ├── verb-slice.R ├── verb-summarise.R ├── verb-uncount.R ├── verb-window.R └── zzz.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── cran-comments.md ├── dbplyr.Rproj ├── inst └── db │ └── .gitignore ├── man ├── arrange.tbl_lazy.Rd ├── backend-access.Rd ├── backend-hana.Rd ├── backend-hive.Rd ├── backend-impala.Rd ├── backend-mssql.Rd ├── backend-mysql.Rd ├── backend-odbc.Rd ├── backend-oracle.Rd ├── backend-postgres.Rd ├── backend-redshift.Rd ├── backend-snowflake.Rd ├── backend-spark-sql.Rd ├── backend-sqlite.Rd ├── backend-teradata.Rd ├── build_sql.Rd ├── collapse.tbl_sql.Rd ├── complete.tbl_lazy.Rd ├── copy_inline.Rd ├── copy_to.src_sql.Rd ├── count.tbl_lazy.Rd ├── db-io.Rd ├── db-misc.Rd ├── db-quote.Rd ├── db-sql.Rd ├── dbplyr-package.Rd ├── dbplyr-slice.Rd ├── dbplyr_uncount.Rd ├── distinct.tbl_lazy.Rd ├── do.tbl_sql.Rd ├── escape.Rd ├── expand.tbl_lazy.Rd ├── figures │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-stable.svg │ ├── lifecycle-superseded.svg │ └── logo.png ├── fill.tbl_lazy.Rd ├── filter.tbl_lazy.Rd ├── get_returned_rows.Rd ├── group_by.tbl_lazy.Rd ├── head.tbl_lazy.Rd ├── ident.Rd ├── ident_q.Rd ├── in_schema.Rd ├── intersect.tbl_lazy.Rd ├── is_table_path.Rd ├── join.tbl_sql.Rd ├── lahman.Rd ├── lazy_ops.Rd ├── memdb_frame.Rd ├── mutate.tbl_lazy.Rd ├── named_commas.Rd ├── nycflights13.Rd ├── partial_eval.Rd ├── pivot_longer.tbl_lazy.Rd ├── pivot_wider.tbl_lazy.Rd ├── pull.tbl_sql.Rd ├── reexports.Rd ├── remote_name.Rd ├── replace_na.tbl_lazy.Rd ├── rows-db.Rd ├── select.tbl_lazy.Rd ├── simulate_dbi.Rd ├── sql.Rd ├── sql_build.Rd ├── sql_expr.Rd ├── sql_options.Rd ├── sql_query_insert.Rd ├── sql_quote.Rd ├── sql_variant.Rd ├── src_dbi.Rd ├── src_sql.Rd ├── summarise.tbl_lazy.Rd ├── tbl.src_dbi.Rd ├── tbl_lazy.Rd ├── tbl_sql.Rd ├── testing.Rd ├── translate_sql.Rd ├── win_over.Rd └── window_order.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── revdep ├── .gitignore ├── README.md ├── check.R ├── cran.md ├── email.yml ├── failures.md └── problems.md ├── tests ├── testthat.R └── testthat │ ├── .gitignore │ ├── _snaps │ ├── backend-.md │ ├── backend-access.md │ ├── backend-hana.md │ ├── backend-hive.md │ ├── backend-impala.md │ ├── backend-mssql.md │ ├── backend-mysql.md │ ├── backend-oracle.md │ ├── backend-postgres.md │ ├── backend-redshift.md │ ├── backend-snowflake.md │ ├── backend-spark-sql.md │ ├── backend-sqlite.md │ ├── backend-teradata.md │ ├── build-sql.md │ ├── db-io.md │ ├── db-sql.md │ ├── escape.md │ ├── ident.md │ ├── lazy-join-query.md │ ├── lazy-select-query.md │ ├── pillar.md │ ├── query-join.md │ ├── query-select.md │ ├── query-semi-join.md │ ├── query-set-op.md │ ├── rows.md │ ├── schema.md │ ├── sql-build.md │ ├── sql.md │ ├── table-name.md │ ├── tbl-lazy.md │ ├── tbl-sql.md │ ├── tidyeval-across.md │ ├── tidyeval.md │ ├── translate-sql-conditional.md │ ├── translate-sql-cut.md │ ├── translate-sql-helpers.md │ ├── translate-sql-quantile.md │ ├── translate-sql-string.md │ ├── translate-sql-window.md │ ├── translate-sql.md │ ├── verb-arrange.md │ ├── verb-compute.md │ ├── verb-copy-to.md │ ├── verb-count.md │ ├── verb-distinct.md │ ├── verb-do.md │ ├── verb-expand.md │ ├── verb-fill.md │ ├── verb-filter.md │ ├── verb-group_by.md │ ├── verb-joins.md │ ├── verb-mutate.md │ ├── verb-pivot-longer.md │ ├── verb-pivot-wider.md │ ├── verb-pull.md │ ├── verb-select.md │ ├── verb-set-ops.md │ ├── verb-slice.md │ ├── verb-summarise.md │ ├── verb-uncount.md │ └── verb-window.md │ ├── helper-src.R │ ├── test-backend-.R │ ├── test-backend-access.R │ ├── test-backend-hana.R │ ├── test-backend-hive.R │ ├── test-backend-impala.R │ ├── test-backend-mssql.R │ ├── test-backend-mysql.R │ ├── test-backend-odbc.R │ ├── test-backend-oracle.R │ ├── test-backend-postgres-old.R │ ├── test-backend-postgres.R │ ├── test-backend-redshift.R │ ├── test-backend-snowflake.R │ ├── test-backend-spark-sql.R │ ├── test-backend-sqlite.R │ ├── test-backend-teradata.R │ ├── test-build-sql.R │ ├── test-db-escape.R │ ├── test-db-io.R │ ├── test-db-sql.R │ ├── test-escape.R │ ├── test-ident.R │ ├── test-lazy-join-query.R │ ├── test-lazy-select-query.R │ ├── test-pillar.R │ ├── test-query-join.R │ ├── test-query-select.R │ ├── test-query-semi-join.R │ ├── test-query-set-op.R │ ├── test-remote.R │ ├── test-rows.R │ ├── test-schema.R │ ├── test-sql-build.R │ ├── test-sql-expr.R │ ├── test-sql.R │ ├── test-src_dbi.R │ ├── test-table-name.R │ ├── test-tbl-lazy.R │ ├── test-tbl-sql.R │ ├── test-tidyeval-across.R │ ├── test-tidyeval.R │ ├── test-translate-sql-conditional.R │ ├── test-translate-sql-cut.R │ ├── test-translate-sql-helpers.R │ ├── test-translate-sql-paste.R │ ├── test-translate-sql-quantile.R │ ├── test-translate-sql-string.R │ ├── test-translate-sql-window.R │ ├── test-translate-sql.R │ ├── test-utils.R │ ├── test-verb-arrange.R │ ├── test-verb-compute.R │ ├── test-verb-copy-to.R │ ├── test-verb-count.R │ ├── test-verb-distinct.R │ ├── test-verb-do.R │ ├── test-verb-expand.R │ ├── test-verb-fill.R │ ├── test-verb-filter.R │ ├── test-verb-group_by.R │ ├── test-verb-head.R │ ├── test-verb-joins.R │ ├── test-verb-mutate.R │ ├── test-verb-pivot-longer.R │ ├── test-verb-pivot-wider.R │ ├── test-verb-pull.R │ ├── test-verb-select.R │ ├── test-verb-set-ops.R │ ├── test-verb-slice.R │ ├── test-verb-summarise.R │ ├── test-verb-uncount.R │ └── test-verb-window.R └── vignettes ├── .gitignore ├── backend-2.Rmd ├── dbplyr.Rmd ├── new-backend.Rmd ├── reprex.Rmd ├── setup ├── _mssql.Rmd ├── _mysql.Rmd ├── _postgres.Rmd └── _sap-hana.Rmd ├── sql.Rmd ├── translation-function.Rmd ├── translation-verb.Rmd ├── windows.graffle └── windows.png /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^CRAN-RELEASE$ 2 | ^pkgdown$ 3 | ^\.covrignore$ 4 | ^.*\.Rproj$ 5 | ^\.Rproj\.user$ 6 | ^\.travis\.yml$ 7 | ^inst/db$ 8 | ^LICENSE\.md$ 9 | ^README\.Rmd$ 10 | ^codecov\.yml$ 11 | ^_pkgdown\.yml$ 12 | ^docs$ 13 | ^cran-comments\.md$ 14 | ^revdep$ 15 | ^\.httr-oauth$ 16 | ^\.github$ 17 | ^CRAN-SUBMISSION$ 18 | -------------------------------------------------------------------------------- /.covrignore: -------------------------------------------------------------------------------- 1 | R/deprec-*.R 2 | R/compat-*.R 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /NEWS.md merge=union 2 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CODEOWNERS for dbplyr 2 | # https://www.tidyverse.org/development/understudies 3 | .github/CODEOWNERS @hadley @edgararuiz 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report or feature request 3 | about: Describe a bug you've seen or make a case for a new feature 4 | --- 5 | 6 | Please briefly describe your problem and what output you expect. If you have a question, please don't use this form. Instead, ask on or . 7 | 8 | Please include a minimal reproducible example (AKA a reprex). If you've never heard of a [reprex](http://reprex.tidyverse.org/) before, start by reading . You can use the examples in [Reprexes for dbplyr](https://dbplyr.tidyverse.org/articles/reprex.html) as a starting point for your reprex. 9 | 10 | Brief description of the problem 11 | 12 | ```r 13 | # insert reprex here 14 | ``` 15 | -------------------------------------------------------------------------------- /.github/move.yml: -------------------------------------------------------------------------------- 1 | # Configuration for move-issues bot - https://github.com/dessant/move-issues 2 | 3 | # Delete the command comment when it contains no other content 4 | deleteCommand: true 5 | 6 | # Close the source issue after moving 7 | closeSourceIssue: true 8 | 9 | # Lock the source issue after moving 10 | lockSourceIssue: false 11 | 12 | # Mention issue and comment authors 13 | mentionAuthors: true 14 | 15 | # Preserve mentions in the issue content 16 | keepContentMentions: true 17 | 18 | # Set custom aliases for targets 19 | # aliases: 20 | # r: repo 21 | # or: owner/repo 22 | -------------------------------------------------------------------------------- /.github/odbc/odbc.ini: -------------------------------------------------------------------------------- 1 | [ODBC Data Sources] 2 | 3 | [MicrosoftSQLServer] 4 | Driver = ODBC Driver 17 for SQL Server 5 | Server = localhost 6 | Port = 1433 7 | Database = test 8 | -------------------------------------------------------------------------------- /.github/odbc/odbcinst.ini: -------------------------------------------------------------------------------- 1 | [ODBC Drivers] 2 | 3 | [ODBC Driver 17 for SQL Server] 4 | Description=Microsoft ODBC Driver 17 for SQL Server 5 | Driver=/usr/lib/libmsodbcsql-17.so 6 | UsageCount=1 7 | -------------------------------------------------------------------------------- /.github/workflows/mssql.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: mssql 10 | 11 | jobs: 12 | mssql: 13 | runs-on: ubuntu-latest 14 | 15 | services: 16 | sqlserver: 17 | image: mcr.microsoft.com/mssql/server:2017-latest-ubuntu 18 | ports: 19 | - 1433:1433 20 | env: 21 | ACCEPT_EULA: Y 22 | SA_PASSWORD: Password12 23 | 24 | env: 25 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true 26 | GITHUB_MSSQL: true 27 | ODBCSYSINI: ${{ github.workspace }}/.github/odbc 28 | 29 | steps: 30 | - uses: actions/checkout@v3 31 | 32 | - uses: r-lib/actions/setup-r@v2 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | use-public-rspm: true 39 | 40 | - uses: r-lib/actions/setup-r-dependencies@v2 41 | with: 42 | extra-packages: any::rcmdcheck 43 | needs: check 44 | 45 | - name: Install SQL Server driver 46 | run: | 47 | curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - 48 | curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list 49 | apt-get update 50 | ACCEPT_EULA=Y apt-get install -y msodbcsql17 51 | sqlcmd -U SA -P 'Password12' -Q 'CREATE DATABASE test;' 52 | dpkg -L msodbcsql17 53 | shell: sudo bash {0} 54 | 55 | - name: Check drivers 56 | run: odbc::odbcListDrivers() 57 | shell: Rscript {0} 58 | 59 | - uses: r-lib/actions/check-r-package@v2 60 | with: 61 | upload-snapshots: true 62 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: ubuntu-latest 17 | # Only restrict concurrency for non-PR jobs 18 | concurrency: 19 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | permissions: 23 | contents: write 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: r-lib/actions/setup-pandoc@v2 28 | 29 | - uses: r-lib/actions/setup-r@v2 30 | with: 31 | use-public-rspm: true 32 | 33 | - uses: r-lib/actions/setup-r-dependencies@v2 34 | with: 35 | extra-packages: any::pkgdown, local::. 36 | needs: website 37 | 38 | - name: Build site 39 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 40 | shell: Rscript {0} 41 | 42 | - name: Deploy to GitHub pages 🚀 43 | if: github.event_name != 'pull_request' 44 | uses: JamesIves/github-pages-deploy-action@v4.4.1 45 | with: 46 | clean: false 47 | branch: gh-pages 48 | folder: docs 49 | -------------------------------------------------------------------------------- /.github/workflows/postgres.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: postgres 10 | 11 | jobs: 12 | postgres: 13 | runs-on: ubuntu-latest 14 | 15 | services: 16 | postgres: 17 | image: postgres 18 | ports: 19 | - 5432:5432 20 | env: 21 | POSTGRES_USER: postgres 22 | POSTGRES_PASSWORD: password 23 | POSTGRES_DB: test 24 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 25 | 26 | env: 27 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true 28 | GITHUB_POSTGRES: true 29 | 30 | steps: 31 | - uses: actions/checkout@v3 32 | 33 | - uses: r-lib/actions/setup-r@v2 34 | 35 | - uses: r-lib/actions/setup-pandoc@v2 36 | 37 | - uses: r-lib/actions/setup-r@v2 38 | with: 39 | use-public-rspm: true 40 | 41 | - uses: r-lib/actions/setup-r-dependencies@v2 42 | with: 43 | extra-packages: any::rcmdcheck 44 | needs: check 45 | 46 | - uses: r-lib/actions/check-r-package@v2 47 | with: 48 | upload-snapshots: true 49 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage.yaml 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | test-coverage: 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - uses: r-lib/actions/setup-r@v2 23 | with: 24 | use-public-rspm: true 25 | 26 | - uses: r-lib/actions/setup-r-dependencies@v2 27 | with: 28 | extra-packages: any::covr, any::xml2 29 | needs: coverage 30 | 31 | - name: Test coverage 32 | run: | 33 | cov <- covr::package_coverage( 34 | quiet = FALSE, 35 | clean = FALSE, 36 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 37 | ) 38 | print(cov) 39 | covr::to_cobertura(cov) 40 | shell: Rscript {0} 41 | 42 | - uses: codecov/codecov-action@v5 43 | with: 44 | # Fail if error if not on PR, or if on PR and token is given 45 | fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }} 46 | files: ./cobertura.xml 47 | plugins: noop 48 | disable_search: true 49 | token: ${{ secrets.CODECOV_TOKEN }} 50 | 51 | - name: Show testthat output 52 | if: always() 53 | run: | 54 | ## -------------------------------------------------------------------- 55 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 56 | shell: bash 57 | 58 | - name: Upload test results 59 | if: failure() 60 | uses: actions/upload-artifact@v4 61 | with: 62 | name: coverage-test-failures 63 | path: ${{ runner.temp }}/package 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /src/*.o 2 | /src/*.o-* 3 | /src/*.d 4 | /src/*.so 5 | *.dll 6 | .RData 7 | .Rproj.user 8 | .Rhistory 9 | inst/doc 10 | .httr-oauth 11 | vignettes/*.R 12 | .DS_Store 13 | /.idea 14 | /clion-test.R 15 | /BROWSE 16 | /GPATH 17 | /GRTAGS 18 | /GTAGS 19 | /TAGS 20 | /.dir-locals.el 21 | revdep/checks 22 | revdep/library 23 | docs 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2023 2 | COPYRIGHT HOLDER: dbplyr authors 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2023 dbplyr authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/backend-impala.R: -------------------------------------------------------------------------------- 1 | #' Backend: Impala 2 | #' 3 | #' @description 4 | #' See `vignette("translation-function")` and `vignette("translation-verb")` for 5 | #' details of overall translation technology. Key differences for this backend 6 | #' are a scattering of custom translations provided by users, mostly focussed 7 | #' on bitwise operations. 8 | #' 9 | #' Use `simulate_impala()` with `lazy_frame()` to see simulated SQL without 10 | #' converting to live access database. 11 | #' 12 | #' @name backend-impala 13 | #' @aliases NULL 14 | #' @examples 15 | #' library(dplyr, warn.conflicts = FALSE) 16 | #' 17 | #' lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_impala()) 18 | #' lf %>% transmute(X = bitwNot(bitwOr(b, c))) 19 | NULL 20 | 21 | #' @export 22 | #' @rdname backend-impala 23 | simulate_impala <- function() simulate_dbi("Impala") 24 | 25 | #' @export 26 | dbplyr_edition.Impala <- function(con) { 27 | 2L 28 | } 29 | 30 | #' @export 31 | sql_translation.Impala <- function(con) { 32 | sql_variant( 33 | scalar = sql_translator(.parent = base_odbc_scalar, 34 | bitwNot = sql_prefix("BITNOT", 1), 35 | bitwAnd = sql_prefix("BITAND", 2), 36 | bitwOr = sql_prefix("BITOR", 2), 37 | bitwXor = sql_prefix("BITXOR", 2), 38 | bitwShiftL = sql_prefix("SHIFTLEFT", 2), 39 | bitwShiftR = sql_prefix("SHIFTRIGHT", 2), 40 | 41 | as.Date = sql_cast("VARCHAR(10)"), 42 | ceiling = sql_prefix("CEIL") 43 | ) , 44 | base_odbc_agg, 45 | base_odbc_win 46 | ) 47 | } 48 | 49 | #' @export 50 | sql_table_analyze.Impala <- function(con, table, ...) { 51 | # Using COMPUTE STATS instead of ANALYZE as recommended in this article 52 | # https://www.cloudera.com/documentation/enterprise/5-9-x/topics/impala_compute_stats.html 53 | glue_sql2(con, "COMPUTE STATS {.tbl table}") 54 | } 55 | -------------------------------------------------------------------------------- /R/data-cache.R: -------------------------------------------------------------------------------- 1 | cache <- function() { 2 | if (!is_attached("dbplyr_cache")) { 3 | get("attach")(new_environment(), name = "dbplyr_cache", pos = length(search()) - 1) 4 | } 5 | search_env("dbplyr_cache") 6 | } 7 | 8 | cache_computation <- function(name, computation) { 9 | cache <- cache() 10 | 11 | if (env_has(cache, name)) { 12 | env_get(cache, name) 13 | } else { 14 | res <- force(computation) 15 | env_poke(cache, name, res) 16 | res 17 | } 18 | } 19 | 20 | # nocov start 21 | load_srcs <- function(f, src_names, quiet = NULL) { 22 | if (is.null(quiet)) { 23 | quiet <- !identical(Sys.getenv("NOT_CRAN"), "true") 24 | } 25 | 26 | srcs <- lapply(src_names, function(x) { 27 | out <- NULL 28 | try(out <- f(x), silent = TRUE) 29 | if (is.null(out) && !quiet) { 30 | message("Could not instantiate ", x, " src") 31 | } 32 | out 33 | }) 34 | 35 | purrr::compact(setNames(srcs, src_names)) 36 | } 37 | 38 | 39 | db_location <- function(path = NULL, filename) { 40 | if (!is.null(path)) { 41 | # Check that path is a directory and is writeable 42 | if (!file.exists(path) || !file.info(path)$isdir) { 43 | cli_abort("{.path {path}} is not a directory") 44 | } 45 | if (!is_writeable(path)) cli_abort("Can not write to {.path {path}}") 46 | return(file.path(path, filename)) 47 | } 48 | 49 | pkg <- file.path(system.file("db", package = "dplyr")) 50 | if (is_writeable(pkg)) return(file.path(pkg, filename)) 51 | 52 | tmp <- tempdir() 53 | if (is_writeable(tmp)) return(file.path(tmp, filename)) 54 | 55 | cli_abort("Could not find writeable location to cache db") 56 | } 57 | 58 | is_writeable <- function(x) { 59 | unname(file.access(x, 2) == 0) 60 | } 61 | # nocov end 62 | -------------------------------------------------------------------------------- /R/db-escape.R: -------------------------------------------------------------------------------- 1 | #' SQL escaping/quoting generics 2 | #' 3 | #' These generics translate individual values into SQL. The core 4 | #' generics are [DBI::dbQuoteIdentifier()] and [DBI::dbQuoteString] 5 | #' for quoting identifiers and strings, but dbplyr needs additional 6 | #' tools for inserting logical, date, date-time, and raw values into 7 | #' queries. 8 | #' 9 | #' @keywords internal 10 | #' @family generic 11 | #' @name db-quote 12 | #' @aliases NULL 13 | #' @examples 14 | #' con <- simulate_dbi() 15 | #' sql_escape_logical(con, c(TRUE, FALSE, NA)) 16 | #' sql_escape_date(con, Sys.Date()) 17 | #' sql_escape_date(con, Sys.time()) 18 | #' sql_escape_raw(con, charToRaw("hi")) 19 | NULL 20 | 21 | #' @rdname db-quote 22 | #' @export 23 | sql_escape_logical <- function(con, x) { 24 | UseMethod("sql_escape_logical") 25 | } 26 | #' @export 27 | sql_escape_logical.DBIConnection <- function(con, x) { 28 | y <- as.character(x) 29 | y[is.na(x)] <- "NULL" 30 | y 31 | } 32 | 33 | #' @export 34 | #' @rdname db-quote 35 | sql_escape_date <- function(con, x) { 36 | UseMethod("sql_escape_date") 37 | } 38 | #' @export 39 | sql_escape_date.DBIConnection <- function(con, x) { 40 | sql_escape_string(con, as.character(x)) 41 | } 42 | 43 | #' @export 44 | #' @rdname db-quote 45 | sql_escape_datetime <- function(con, x) { 46 | UseMethod("sql_escape_datetime") 47 | } 48 | #' @export 49 | sql_escape_datetime.DBIConnection <- function(con, x) { 50 | x <- strftime(x, "%Y-%m-%dT%H:%M:%OSZ", tz = "UTC") 51 | sql_escape_string(con, x) 52 | } 53 | 54 | #' @export 55 | #' @rdname db-quote 56 | sql_escape_raw <- function(con, x) { 57 | UseMethod("sql_escape_raw") 58 | } 59 | #' @export 60 | sql_escape_raw.DBIConnection <- function(con, x) { 61 | # Unlike the other escape functions, this is not vectorised because 62 | # raw "vectors" are scalars in this content 63 | 64 | if (is.null(x)) { 65 | "NULL" 66 | } else { 67 | # SQL-99 standard for BLOB literals 68 | # https://crate.io/docs/sql-99/en/latest/chapters/05.html#blob-literal-s 69 | paste0(c("X'", format(x), "'"), collapse = "") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /R/dbplyr.R: -------------------------------------------------------------------------------- 1 | #' @importFrom stats setNames update 2 | #' @importFrom utils head tail 3 | #' @importFrom glue glue 4 | #' @importFrom cli cli_abort 5 | #' @importFrom dplyr n join_by 6 | #' @import rlang 7 | #' @import DBI 8 | #' @importFrom tibble tibble as_tibble 9 | #' @importFrom magrittr %>% 10 | #' @importFrom lifecycle deprecated 11 | #' @keywords internal 12 | "_PACKAGE" 13 | -------------------------------------------------------------------------------- /R/explain.R: -------------------------------------------------------------------------------- 1 | #' @importFrom dplyr show_query 2 | #' @export 3 | show_query.tbl_lazy <- function(x, ..., cte = FALSE, sql_options = NULL) { 4 | withr::local_options(list(dbplyr_use_colour = TRUE)) 5 | sql <- remote_query(x, cte = cte, sql_options = sql_options) 6 | cat_line("") 7 | cat_line(sql) 8 | invisible(x) 9 | } 10 | 11 | #' @importFrom dplyr explain 12 | #' @export 13 | explain.tbl_sql <- function(x, ...) { 14 | force(x) 15 | show_query(x) 16 | cat_line() 17 | cat_line("") 18 | cat_line(remote_query_plan(x, ...)) 19 | 20 | invisible(x) 21 | } 22 | -------------------------------------------------------------------------------- /R/ident.R: -------------------------------------------------------------------------------- 1 | #' Flag a character vector as SQL identifiers 2 | #' 3 | #' @description 4 | #' `ident()` takes strings and turns them as database identifiers (e.g. table 5 | #' or column names) quoting them using the identifer rules for your database. 6 | #' `ident_q()` does the same, but assumes the names have already been 7 | #' quoted, preventing them from being quoted again. 8 | #' 9 | #' These are generally for internal use only; if you need to supply an 10 | #' table name that is qualified with schema or catalog, or has already been 11 | #' quoted for some other reason, use `I()`. 12 | #' 13 | #' @param ... A character vector, or name-value pairs. 14 | #' @param x An object. 15 | #' @keywords internal 16 | #' @export 17 | #' @examples 18 | #' # SQL92 quotes strings with ' 19 | #' escape_ansi("x") 20 | #' 21 | #' # And identifiers with " 22 | #' ident("x") 23 | #' escape_ansi(ident("x")) 24 | #' 25 | #' # You can supply multiple inputs 26 | #' ident(a = "x", b = "y") 27 | #' ident_q(a = "x", b = "y") 28 | ident <- function(...) { 29 | x <- c_character(...) 30 | structure(x, class = c("ident", "character")) 31 | } 32 | 33 | #' @export 34 | print.ident <- function(x, ...) cat(format(x, ...), sep = "\n") 35 | #' @export 36 | format.ident <- function(x, ...) { 37 | if (length(x) == 0) { 38 | paste0(" [empty]") 39 | } else { 40 | paste0(" ", x) 41 | } 42 | } 43 | 44 | #' @rdname ident 45 | #' @export 46 | is.ident <- function(x) inherits(x, "ident") 47 | 48 | -------------------------------------------------------------------------------- /R/lazy-query.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | #' @rdname sql_build 3 | lazy_query <- function(query_type, 4 | x, 5 | ..., 6 | group_vars = op_grps(x), 7 | order_vars = op_sort(x), 8 | frame = op_frame(x)) { 9 | stopifnot(is.null(group_vars) || (is.character(group_vars) && is.null(names(group_vars)))) 10 | stopifnot(is_lazy_sql_part(order_vars), is.null(names(order_vars))) 11 | check_frame(frame) 12 | 13 | structure( 14 | list( 15 | x = x, 16 | ..., 17 | group_vars = group_vars, 18 | order_vars = order_vars, 19 | frame = frame 20 | ), 21 | class = c(paste0("lazy_", query_type, "_query"), "lazy_query") 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /R/memdb.R: -------------------------------------------------------------------------------- 1 | #' Create a database table in temporary in-memory database. 2 | #' 3 | #' `memdb_frame()` works like [tibble::tibble()], but instead of creating a new 4 | #' data frame in R, it creates a table in [src_memdb()]. 5 | #' 6 | #' @inheritParams tibble::tibble 7 | #' @param name,.name Name of table in database: defaults to a random name that's 8 | #' unlikely to conflict with an existing table. 9 | #' @param df Data frame to copy 10 | #' @export 11 | #' @examples 12 | #' library(dplyr) 13 | #' df <- memdb_frame(x = runif(100), y = runif(100)) 14 | #' df %>% arrange(x) 15 | #' df %>% arrange(x) %>% show_query() 16 | #' 17 | #' mtcars_db <- tbl_memdb(mtcars) 18 | #' mtcars_db %>% group_by(cyl) %>% summarise(n = n()) %>% show_query() 19 | memdb_frame <- function(..., .name = unique_table_name()) { 20 | x <- copy_to(src_memdb(), tibble(...), name = .name) 21 | x 22 | } 23 | 24 | #' @rdname memdb_frame 25 | #' @export 26 | tbl_memdb <- function(df, name = deparse(substitute(df))) { 27 | copy_to(src_memdb(), df, name = name) # nocov 28 | } 29 | 30 | #' @rdname memdb_frame 31 | #' @export 32 | src_memdb <- function() { 33 | cache_computation("src_memdb", { 34 | src_dbi(DBI::dbConnect(RSQLite::SQLite(), ":memory:", create = TRUE)) 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /R/optimise-utils.R: -------------------------------------------------------------------------------- 1 | uses_mutated_vars <- function(dots, select) { 2 | if (is_null(select)) { 3 | return(TRUE) 4 | } 5 | 6 | vars <- set_names(select$expr, select$name) 7 | mutated_vars <- names(purrr::discard(vars, is_symbol)) 8 | 9 | if (is_empty(mutated_vars)) { 10 | return(FALSE) 11 | } 12 | 13 | any(purrr::map_lgl(dots, expr_uses_var, mutated_vars)) 14 | } 15 | 16 | expr_uses_var <- function(x, vars) { 17 | if (is.sql(x)) return(TRUE) 18 | if (is_call(x, "sql")) return(TRUE) 19 | if (is_quosure(x)) return(expr_uses_var(quo_get_expr(x), vars)) 20 | if (is_symbol(x)) { 21 | return(is_symbol(x, vars)) 22 | } 23 | 24 | any(purrr::map_lgl(as.list(x[-1]), expr_uses_var, vars)) 25 | } 26 | 27 | any_expr_uses_sql <- function(dots) { 28 | purrr::some(dots, expr_uses_sql) 29 | } 30 | 31 | expr_uses_sql <- function(x) { 32 | if (is.sql(x)) return(TRUE) 33 | if (is_call(x, "sql")) return(TRUE) 34 | if (is_quosure(x)) return(expr_uses_sql(quo_get_expr(x))) 35 | 36 | if (!is_call(x)) return(FALSE) 37 | 38 | any(purrr::map_lgl(as.list(x[-1]), expr_uses_sql)) 39 | } 40 | -------------------------------------------------------------------------------- /R/pillar.R: -------------------------------------------------------------------------------- 1 | #' @importFrom pillar tbl_format_header style_subtle align 2 | #' @export 3 | tbl_format_header.tbl_sql <- function(x, setup, ...) { 4 | named_header <- tbl_sum(x) 5 | 6 | # The setup object may know the total number of rows 7 | named_header["Source"] <- tbl_desc(x, rows_total = setup$rows_total) 8 | 9 | # Adapted from pillar 10 | header <- paste0( 11 | align(paste0(names(named_header), ":")), 12 | " ", 13 | named_header 14 | ) 15 | 16 | style_subtle(paste0("# ", header)) 17 | } 18 | -------------------------------------------------------------------------------- /R/query-semi-join.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | #' @rdname sql_build 3 | semi_join_query <- function(x, 4 | y, 5 | vars, 6 | anti = FALSE, 7 | by = NULL, 8 | where = NULL, 9 | na_matches = FALSE) { 10 | structure( 11 | list( 12 | x = x, 13 | y = y, 14 | vars = vars, 15 | anti = anti, 16 | by = by, 17 | where = where, 18 | na_matches = na_matches 19 | ), 20 | class = c("semi_join_query", "query") 21 | ) 22 | } 23 | 24 | #' @export 25 | print.semi_join_query <- function(x, ...) { 26 | cat_line("") 27 | 28 | cat_line("By:") 29 | cat_line(indent(paste0(x$by$x, "-", x$by$y))) 30 | 31 | if (length(x$where)) { 32 | cat_line("Where:") 33 | where <- purrr::map_chr(x$where, as_label) 34 | cat_line(indent(paste0(where))) 35 | } 36 | 37 | cat_line("X:") 38 | cat_line(indent_print(x$x)) 39 | 40 | cat_line("Y:") 41 | cat_line(indent_print(x$y)) 42 | } 43 | 44 | #' @export 45 | sql_render.semi_join_query <- function(query, 46 | con = NULL, 47 | ..., 48 | sql_options = NULL, 49 | subquery = FALSE, 50 | lvl = 0) { 51 | from_x <- sql_render(query$x, con, ..., subquery = TRUE, lvl = lvl + 1) 52 | from_y <- sql_render(query$y, con, ..., subquery = TRUE, lvl = lvl + 1) 53 | 54 | dbplyr_query_semi_join( 55 | con, 56 | from_x, 57 | from_y, 58 | vars = query$vars, 59 | anti = query$anti, 60 | by = query$by, 61 | where = query$where, 62 | lvl = lvl 63 | ) 64 | } 65 | 66 | #' @export 67 | flatten_query.semi_join_query <- flatten_query_2_tables 68 | -------------------------------------------------------------------------------- /R/query.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | sql_optimise.query <- function(x, con = NULL, ...) { 3 | # Default to no optimisation 4 | x 5 | } 6 | -------------------------------------------------------------------------------- /R/reexport.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | magrittr::`%>%` 3 | -------------------------------------------------------------------------------- /R/simulate.R: -------------------------------------------------------------------------------- 1 | #' Simulate database connections 2 | #' 3 | #' These functions generate S3 objects that have been designed to simulate 4 | #' the action of a database connection, without actually having the database 5 | #' available. Obviously, this simulation can only be incomplete, but most 6 | #' importantly it allows us to simulate SQL generation for any database without 7 | #' actually connecting to it. 8 | #' 9 | #' Simulated SQL always quotes identifies with `` `x` ``, and strings with 10 | #' `'x'`. 11 | #' 12 | #' @keywords internal 13 | #' @export 14 | simulate_dbi <- function(class = character(), ...) { 15 | structure( 16 | list(), 17 | ..., 18 | class = c(class, "TestConnection", "DBIConnection") 19 | ) 20 | } 21 | 22 | #' @export 23 | dbplyr_edition.TestConnection <- function(con) 2L 24 | 25 | 26 | sql_escape_ident <- function(con, x) { 27 | UseMethod("sql_escape_ident") 28 | } 29 | #' @export 30 | sql_escape_ident.default <- function(con, x) { 31 | dbQuoteIdentifier(con, x) 32 | } 33 | #' @export 34 | sql_escape_ident.TestConnection <- function(con, x) { 35 | if (methods::is(x, "SQL")) { 36 | x 37 | } else { 38 | sql_quote(x, "`") 39 | } 40 | } 41 | 42 | sql_escape_string <- function(con, x) { 43 | UseMethod("sql_escape_string") 44 | } 45 | #' @export 46 | sql_escape_string.default <- function(con, x) { 47 | dbQuoteString(con, x) 48 | } 49 | #' @export 50 | sql_escape_string.TestConnection <- function(con, x) { 51 | sql_quote(x, "'") 52 | } 53 | -------------------------------------------------------------------------------- /R/sql.R: -------------------------------------------------------------------------------- 1 | #' SQL escaping. 2 | #' 3 | #' These functions are critical when writing functions that translate R 4 | #' functions to sql functions. Typically a conversion function should escape 5 | #' all its inputs and return an sql object. 6 | #' 7 | #' @param ... Character vectors that will be combined into a single SQL 8 | #' expression. 9 | #' @export 10 | sql <- function(...) { 11 | x <- c_character(...) 12 | structure(x, class = c("sql", "character")) 13 | } 14 | 15 | # See setOldClass definition in zzz.R 16 | 17 | # c() is also called outside of the dbplyr context so must supply default 18 | # connection - this seems like a design mistake, and probably an indication 19 | # that within dbplyr c() should be replaced with a more specific function 20 | #' @export 21 | c.sql <- function(..., drop_null = FALSE, con = simulate_dbi()) { 22 | input <- list(...) 23 | 24 | if (drop_null) input <- purrr::compact(input) # nocov 25 | 26 | out <- unlist(lapply(input, escape, collapse = NULL, con = con)) 27 | sql(out) 28 | } 29 | 30 | #' @export 31 | c.ident <- c.sql 32 | 33 | #' @export 34 | unique.sql <- function(x, ...) { 35 | sql(NextMethod()) # nocov 36 | } 37 | 38 | #' @rdname sql 39 | #' @export 40 | is.sql <- function(x) inherits(x, "sql") 41 | 42 | #' @export 43 | print.sql <- function(x, ...) cat(format(x, ...), sep = "\n") 44 | #' @export 45 | format.sql <- function(x, ...) { 46 | if (length(x) == 0) { 47 | paste0(" [empty]") 48 | } else { 49 | paste0(" ", x, ifelse(names2(x) == "", "", paste0(" AS ", names2(x)))) 50 | } 51 | } 52 | 53 | #' @rdname sql 54 | #' @export 55 | #' @param x Object to coerce 56 | #' @param con Needed when `x` is directly supplied from the user so that 57 | #' schema specifications can be quoted using the correct identifiers. 58 | as.sql <- function(x, con) UseMethod("as.sql") 59 | 60 | #' @export 61 | as.sql.ident <- function(x, con) x 62 | #' @export 63 | as.sql.sql <- function(x, con) x 64 | #' @export 65 | as.sql.character <- function(x, con) ident(x) 66 | -------------------------------------------------------------------------------- /R/src-sql.R: -------------------------------------------------------------------------------- 1 | # nocov start 2 | 3 | #' Create a "sql src" object 4 | #' 5 | #' Deprecated: please use directly use a `DBIConnection` object instead. 6 | #' 7 | #' @keywords internal 8 | #' @export 9 | #' @param subclass name of subclass. "src_sql" is an abstract base class, so you 10 | #' must supply this value. `src_` is automatically prepended to the 11 | #' class name 12 | #' @param con the connection object 13 | #' @param ... fields used by object 14 | src_sql <- function(subclass, con, ...) { 15 | lifecycle::deprecate_stop( 16 | when = "1.4.0", 17 | what = "src_sql()", 18 | always = TRUE 19 | ) 20 | } 21 | 22 | 23 | #' @importFrom dplyr same_src 24 | #' @export 25 | same_src.src_sql <- function(x, y) { 26 | if (!inherits(y, "src_sql")) return(FALSE) 27 | identical(x$con, y$con) 28 | } 29 | 30 | #' @importFrom dplyr src_tbls 31 | #' @export 32 | src_tbls.src_sql <- function(x, ...) { 33 | dbListTables(x$con) 34 | } 35 | 36 | #' @export 37 | format.src_sql <- function(x, ...) { 38 | paste0( 39 | "src: ", dbplyr_connection_describe(x$con), "\n", 40 | wrap("tbls: ", paste0(sort(src_tbls(x)), collapse = ", ")) 41 | ) 42 | } 43 | # nocov end 44 | -------------------------------------------------------------------------------- /R/testthat.R: -------------------------------------------------------------------------------- 1 | 2 | compare_tbl <- function(x, y, label = NULL, expected.label = NULL) { 3 | testthat::expect_equal( 4 | arrange(collect(x), dplyr::across(everything())), 5 | arrange(collect(y), dplyr::across(everything())), 6 | label = label, 7 | expected.label = expected.label 8 | ) 9 | } 10 | 11 | expect_equal_tbls <- function(results, ref = NULL, ...) { 12 | check_list(results) 13 | 14 | if (!is_named(results)) { 15 | result_name <- expr_name(substitute(results)) # nocov 16 | names(results) <- paste0(result_name, "_", seq_along(results)) # nocov 17 | } 18 | 19 | # If ref is NULL, use the first result 20 | if (is.null(ref)) { 21 | if (length(results) < 2) { 22 | testthat::skip("Need at least two srcs to compare") 23 | } 24 | 25 | ref <- results[[1]] 26 | ref_name <- names(results)[[1]] 27 | 28 | rest <- results[-1] 29 | } else { 30 | rest <- results 31 | ref_name <- "`ref`" 32 | } 33 | 34 | for (i in seq_along(rest)) { 35 | compare_tbl( 36 | rest[[i]], ref, 37 | label = names(rest)[[i]], 38 | expected.label = ref_name 39 | ) 40 | } 41 | 42 | invisible(TRUE) 43 | } 44 | -------------------------------------------------------------------------------- /R/translate-sql-paste.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | #' @rdname sql_variant 3 | sql_paste <- function(default_sep, f = "CONCAT_WS") { 4 | 5 | function(..., sep = default_sep, collapse = NULL){ 6 | check_collapse(collapse) 7 | sql_call2(f, sep, ...) 8 | } 9 | } 10 | 11 | #' @export 12 | #' @rdname sql_variant 13 | sql_paste_infix <- function(default_sep, op, cast) { 14 | force(default_sep) 15 | op <- as.symbol(paste0("%", op, "%")) 16 | force(cast) 17 | 18 | function(..., sep = default_sep, collapse = NULL){ 19 | check_collapse(collapse) 20 | 21 | args <- list(...) 22 | if (length(args) == 1) { 23 | return(cast(args[[1]])) 24 | } 25 | 26 | if (sep == "") { 27 | infix <- function(x, y) sql_call2(op, x, y) 28 | } else { 29 | infix <- function(x, y) sql_call2(op, sql_call2(op, x, sep), y) 30 | } 31 | 32 | purrr::reduce(args, infix) 33 | } 34 | } 35 | 36 | check_collapse <- function(collapse) { 37 | if (is.null(collapse)) 38 | return() 39 | 40 | cli_abort(c( 41 | "{.arg collapse} not supported in DB translation of {.fun paste}.", 42 | i = "Please use {.fun str_flatten} instead." 43 | )) 44 | } 45 | -------------------------------------------------------------------------------- /R/translate-sql-quantile.R: -------------------------------------------------------------------------------- 1 | sql_quantile <- function(f, 2 | style = c("infix", "ordered"), 3 | window = FALSE) { 4 | force(f) 5 | style <- match.arg(style) 6 | force(window) 7 | 8 | function(x, probs, na.rm = FALSE) { 9 | check_probs(probs) 10 | check_na_rm(na.rm) 11 | 12 | sql <- switch(style, 13 | infix = sql_call2(f, x, probs), 14 | ordered = glue_sql2( 15 | sql_current_con(), 16 | sql_call2(f, probs), " WITHIN GROUP (ORDER BY {x})" 17 | ) 18 | ) 19 | 20 | if (window) { 21 | sql <- win_over(sql, 22 | partition = win_current_group(), 23 | frame = win_current_frame() 24 | ) 25 | } 26 | sql 27 | } 28 | } 29 | 30 | sql_median <- function(f, 31 | style = c("infix", "ordered"), 32 | window = FALSE) { 33 | quantile <- sql_quantile(f, style = style, window = window) 34 | function(x, na.rm = FALSE) { 35 | quantile(x, 0.5, na.rm = na.rm) 36 | } 37 | } 38 | 39 | check_probs <- function(probs, call = caller_env()) { 40 | # TODO min, max? Inf? NA? 41 | check_number_decimal(probs, call = call) 42 | 43 | if (length(probs) > 1) { 44 | cli_abort("SQL translation only supports single value for {.arg probs}.") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /R/utils-format.R: -------------------------------------------------------------------------------- 1 | # nocov start 2 | wrap <- function(..., indent = 0) { 3 | x <- paste0(..., collapse = "") 4 | wrapped <- strwrap( 5 | x, 6 | indent = indent, 7 | exdent = indent + 2, 8 | width = getOption("width") 9 | ) 10 | 11 | paste0(wrapped, collapse = "\n") 12 | } 13 | # nocov end 14 | 15 | indent <- function(x) { 16 | x <- paste0(x, collapse = "\n") 17 | paste0(" ", gsub("\n", "\n ", x)) 18 | } 19 | 20 | indent_print <- function(x) { 21 | indent(utils::capture.output(print(x))) 22 | } 23 | 24 | style_kw <- function(x) { 25 | if (!dbplyr_use_colour()) { 26 | return(x) 27 | } 28 | 29 | highlight <- dbplyr_highlight() 30 | if (is_false(highlight)) { 31 | return(x) 32 | } 33 | 34 | highlight(x) 35 | } 36 | 37 | # function for the thousand separator, 38 | # returns "," unless it's used for the decimal point, in which case returns "." 39 | 'big_mark' <- function(x, ...) { 40 | mark <- if (identical(getOption("OutDec"), ",")) "." else "," 41 | formatC(x, big.mark = mark, ...) 42 | } 43 | 44 | dbplyr_use_colour <- function() { 45 | getOption("dbplyr_use_colour", FALSE) 46 | } 47 | 48 | dbplyr_highlight <- function() { 49 | highlight <- getOption("dbplyr_highlight", cli::combine_ansi_styles("blue")) 50 | 51 | if (is_true(highlight)) { 52 | highlight <- cli::combine_ansi_styles("blue") 53 | } 54 | 55 | if (is_false(highlight)) { 56 | return(FALSE) 57 | } 58 | 59 | if (!inherits(highlight, "cli_ansi_style")) { 60 | msg <- "{.envvar dbplyr_highlight} must be `NULL`, `FALSE` or a {.cls cli_ansi_style}." 61 | cli::cli_abort(msg) 62 | } 63 | 64 | highlight 65 | } 66 | -------------------------------------------------------------------------------- /R/verb-do-query.R: -------------------------------------------------------------------------------- 1 | #' @importFrom R6 R6Class 2 | NULL 3 | 4 | Query <- R6::R6Class("Query", 5 | private = list( 6 | .vars = NULL 7 | ), 8 | public = list( 9 | con = NULL, 10 | sql = NULL, 11 | 12 | initialize = function(con, sql, vars) { 13 | self$con <- con 14 | self$sql <- sql 15 | private$.vars <- vars 16 | }, 17 | 18 | # nocov start 19 | print = function(...) { 20 | cat_line(" ", self$sql) 21 | print(self$con) 22 | }, 23 | 24 | fetch = function(n = -1L) { 25 | res <- dbSendQuery(self$con, self$sql) 26 | on.exit(dbClearResult(res)) 27 | 28 | out <- dbFetch(res, n) 29 | res_warn_incomplete(res) 30 | out 31 | }, 32 | # nocov end 33 | 34 | fetch_paged = function(chunk_size = 1e4, callback) { 35 | qry <- dbSendQuery(self$con, self$sql) 36 | on.exit(dbClearResult(qry)) 37 | 38 | while (!dbHasCompleted(qry)) { 39 | chunk <- dbFetch(qry, chunk_size) 40 | callback(chunk) 41 | } 42 | 43 | invisible(TRUE) 44 | }, 45 | 46 | # nocov start 47 | vars = function() { 48 | private$.vars 49 | }, 50 | 51 | ncol = function() { 52 | length(self$vars()) 53 | } 54 | # nocov end 55 | ) 56 | ) 57 | -------------------------------------------------------------------------------- /R/verb-head.R: -------------------------------------------------------------------------------- 1 | #' Subset the first rows 2 | #' 3 | #' @description 4 | #' This is a method for the [head()] generic. It is usually translated to the 5 | #' `LIMIT` clause of the SQL query. Because `LIMIT` is not an official part of 6 | #' the SQL specification, some database use other clauses like `TOP` or 7 | #' `FETCH ROWS`. 8 | #' 9 | #' Note that databases don't really have a sense of row order, so what "first" 10 | #' means is subject to interpretation. Most databases will respect ordering 11 | #' performed with `arrange()`, but it's not guaranteed. `tail()` is not 12 | #' supported at all because the situation is even murkier for the "last" rows. 13 | #' 14 | #' @param x A lazy data frame backed by a database query. 15 | #' @param n Number of rows to return 16 | #' @param ... Not used. 17 | #' @inherit arrange.tbl_lazy return 18 | #' @export 19 | #' @examples 20 | #' library(dplyr, warn.conflicts = FALSE) 21 | #' 22 | #' db <- memdb_frame(x = 1:100) 23 | #' db %>% head() %>% show_query() 24 | #' 25 | #' # Pretend we have data in a SQL server database 26 | #' db2 <- lazy_frame(x = 1:100, con = simulate_mssql()) 27 | #' db2 %>% head() %>% show_query() 28 | head.tbl_lazy <- function(x, n = 6L, ...) { 29 | if (!is.numeric(n) || length(n) != 1L || n < 0) { 30 | cli_abort("{.arg n} must be a non-negative integer") 31 | } 32 | n <- trunc(n) 33 | 34 | x$lazy_query <- add_head(x, n) 35 | x 36 | } 37 | 38 | add_head <- function(x, n) { 39 | lazy_query <- x$lazy_query 40 | if (!is_lazy_select_query(lazy_query)) { 41 | lazy_query <- lazy_select_query( 42 | x = lazy_query, 43 | limit = n 44 | ) 45 | 46 | return(lazy_query) 47 | } 48 | 49 | lazy_query$limit <- min(lazy_query$limit, n) 50 | lazy_query 51 | } 52 | 53 | #' @export 54 | tail.tbl_lazy <- function(x, n = 6L, ...) { 55 | stop_unsupported_function("tail") 56 | } 57 | -------------------------------------------------------------------------------- /R/verb-pull.R: -------------------------------------------------------------------------------- 1 | #' Extract a single column 2 | #' 3 | #' This is a method for the dplyr [pull()] generic. It evaluates the query 4 | #' retrieving just the specified column. 5 | #' 6 | #' @inheritParams arrange.tbl_lazy 7 | #' @inheritParams dplyr::pull 8 | #' @return A vector of data. 9 | #' @importFrom dplyr pull 10 | #' @export 11 | #' @examples 12 | #' library(dplyr, warn.conflicts = FALSE) 13 | #' 14 | #' db <- memdb_frame(x = 1:5, y = 5:1) 15 | #' db %>% 16 | #' mutate(z = x + y * 2) %>% 17 | #' pull() 18 | pull.tbl_sql <- function(.data, var = -1, name = NULL, ...) { 19 | vars <- tbl_vars(.data) 20 | var <- tidyselect::vars_pull(vars, !!enquo(var), error_arg = "var") 21 | name_quo <- enquo(name) 22 | if (!quo_is_null(name_quo)) { 23 | name <- tidyselect::vars_pull(vars, !!name_quo, error_arg = "name") 24 | } 25 | 26 | .data <- ungroup(.data) 27 | .data <- select(.data, all_of(c(var, name))) 28 | 29 | .data <- collect(.data) 30 | out <- .data[[var]] 31 | if (!is.null(name)) { 32 | out <- set_names(out, nm = .data[[name]]) 33 | } 34 | 35 | out 36 | } 37 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | # nocov start 2 | .onLoad <- function(...) { 3 | # lazy S3method() directive for this case only works in 4.3 and later 4 | s3_register("dplyr::filter", "tbl_lazy") 5 | 6 | methods::setOldClass(c("ident_q", "ident", "character"), ident_q()) 7 | methods::setOldClass(c("ident", "character"), ident()) 8 | methods::setOldClass(c("sql", "character"), sql()) 9 | 10 | base_scalar$`%>%` <- magrittr::`%>%` 11 | } 12 | 13 | # Silence R CMD check note: 14 | # ** checking whether the namespace can be loaded with stated dependencies ... NOTE 15 | # Warning in .undefineMethod("initialize", Class, classWhere) : 16 | # no generic function 'initialize' found 17 | # 18 | # I'm not sure why this is necessary, but I suspect it's due to the use of 19 | # setOldClass onLoad 20 | #' @importFrom methods initialize 21 | NULL 22 | 23 | # nocov end 24 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## R CMD check results 2 | 3 | 0 errors | 0 warnings | 1 notes 4 | 5 | Just the usual maintainer email address change. 6 | 7 | ## revdepcheck results 8 | 9 | We checked 101 reverse dependencies (92 from CRAN + 9 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 10 | 11 | * We saw 8 new problems: 12 | 13 | Andromeda: fix submitted at https://github.com/OHDSI/Andromeda/pull/63 14 | 15 | CMDConnector: fix submitted at https://github.com/darwin-eu/CDMConnector/pull/16 16 | 17 | CohortSurvival/DrugUtilisation/IncidencePrevalence/PatientProfiles: 18 | Failure due CDMConnector 19 | 20 | SCDB: fix submitted at https://github.com/ssi-dk/SCDB/pull/114 21 | 22 | diseasystore: due to SCDB 23 | 24 | * We failed to check 0 packages 25 | 26 | The authors of failing packages have been contacted, and most have been supplied with patches. Detailed summarised at https://github.com/tidyverse/dbplyr/issues/1469 27 | -------------------------------------------------------------------------------- /dbplyr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source --install-tests 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /inst/db/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /man/arrange.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-arrange.R 3 | \name{arrange.tbl_lazy} 4 | \alias{arrange.tbl_lazy} 5 | \title{Arrange rows by column values} 6 | \usage{ 7 | \method{arrange}{tbl_lazy}(.data, ..., .by_group = FALSE) 8 | } 9 | \arguments{ 10 | \item{.data}{A lazy data frame backed by a database query.} 11 | 12 | \item{...}{<\code{\link[rlang:args_data_masking]{data-masking}}> Variables, or 13 | functions of variables. Use \code{\link[dplyr:desc]{desc()}} to sort a variable in descending 14 | order.} 15 | 16 | \item{.by_group}{If \code{TRUE}, will sort first by grouping variable. Applies to 17 | grouped data frames only.} 18 | } 19 | \value{ 20 | Another \code{tbl_lazy}. Use \code{\link[=show_query]{show_query()}} to see the generated 21 | query, and use \code{\link[=collect.tbl_sql]{collect()}} to execute the query 22 | and return data to R. 23 | } 24 | \description{ 25 | This is an method for the dplyr \code{\link[=arrange]{arrange()}} generic. It generates 26 | the \verb{ORDER BY} clause of the SQL query. It also affects the 27 | \code{\link[=window_order]{window_order()}} of windowed expressions in \code{\link[=mutate.tbl_lazy]{mutate.tbl_lazy()}}. 28 | 29 | Note that \verb{ORDER BY} clauses can not generally appear in subqueries, which 30 | means that you should \code{arrange()} as late as possible in your pipelines. 31 | } 32 | \section{Missing values}{ 33 | 34 | Unlike R, most databases sorts \code{NA} (\code{NULL}s) at the front. You can 35 | can override this behaviour by explicitly sorting on \code{is.na(x)}. 36 | } 37 | 38 | \examples{ 39 | library(dplyr, warn.conflicts = FALSE) 40 | 41 | db <- memdb_frame(a = c(3, 4, 1, 2), b = c(5, 1, 2, NA)) 42 | db \%>\% arrange(a) \%>\% show_query() 43 | 44 | # Note that NAs are sorted first 45 | db \%>\% arrange(b) 46 | # override by sorting on is.na() first 47 | db \%>\% arrange(is.na(b), b) 48 | } 49 | -------------------------------------------------------------------------------- /man/backend-access.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-access.R 3 | \name{backend-access} 4 | \alias{simulate_access} 5 | \title{Backend: MS Access} 6 | \usage{ 7 | simulate_access() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are: 13 | \itemize{ 14 | \item \code{SELECT} uses \code{TOP}, not \code{LIMIT} 15 | \item Non-standard types and mathematical functions 16 | \item String concatenation uses \code{&} 17 | \item No \code{ANALYZE} equivalent 18 | \item \code{TRUE} and \code{FALSE} converted to 1 and 0 19 | } 20 | 21 | Use \code{simulate_access()} with \code{lazy_frame()} to see simulated SQL without 22 | converting to live access database. 23 | } 24 | \examples{ 25 | library(dplyr, warn.conflicts = FALSE) 26 | lf <- lazy_frame(x = 1, y = 2, z = "a", con = simulate_access()) 27 | 28 | lf \%>\% head() 29 | lf \%>\% mutate(y = as.numeric(y), z = sqrt(x^2 + 10)) 30 | lf \%>\% mutate(a = paste0(z, " times")) 31 | } 32 | -------------------------------------------------------------------------------- /man/backend-hana.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-hana.R 3 | \name{backend-hana} 4 | \alias{simulate_hana} 5 | \title{Backend: SAP HANA} 6 | \usage{ 7 | simulate_hana() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are: 13 | \itemize{ 14 | \item Temporary tables get \verb{#} prefix and use \verb{LOCAL TEMPORARY COLUMN}. 15 | \item No table analysis performed in \code{\link[=copy_to]{copy_to()}}. 16 | \item \code{paste()} uses \code{||} 17 | \item Note that you can't create new boolean columns from logical expressions; 18 | you need to wrap with explicit \code{ifelse}: \code{ifelse(x > y, TRUE, FALSE)}. 19 | } 20 | 21 | Use \code{simulate_hana()} with \code{lazy_frame()} to see simulated SQL without 22 | converting to live access database. 23 | } 24 | \examples{ 25 | library(dplyr, warn.conflicts = FALSE) 26 | 27 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_hana()) 28 | lf \%>\% transmute(x = paste0(d, " times")) 29 | } 30 | -------------------------------------------------------------------------------- /man/backend-hive.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-hive.R 3 | \name{backend-hive} 4 | \alias{simulate_hive} 5 | \title{Backend: Hive} 6 | \usage{ 7 | simulate_hive() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are a scattering of custom translations provided by users. 13 | 14 | Use \code{simulate_hive()} with \code{lazy_frame()} to see simulated SQL without 15 | converting to live access database. 16 | } 17 | \examples{ 18 | library(dplyr, warn.conflicts = FALSE) 19 | 20 | lf <- lazy_frame(a = TRUE, b = 1, d = 2, c = "z", con = simulate_hive()) 21 | lf \%>\% transmute(x = cot(b)) 22 | lf \%>\% transmute(x = bitwShiftL(c, 1L)) 23 | lf \%>\% transmute(x = str_replace_all(c, "a", "b")) 24 | 25 | lf \%>\% summarise(x = median(d, na.rm = TRUE)) 26 | lf \%>\% summarise(x = var(c, na.rm = TRUE)) 27 | } 28 | -------------------------------------------------------------------------------- /man/backend-impala.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-impala.R 3 | \name{backend-impala} 4 | \alias{simulate_impala} 5 | \title{Backend: Impala} 6 | \usage{ 7 | simulate_impala() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are a scattering of custom translations provided by users, mostly focussed 13 | on bitwise operations. 14 | 15 | Use \code{simulate_impala()} with \code{lazy_frame()} to see simulated SQL without 16 | converting to live access database. 17 | } 18 | \examples{ 19 | library(dplyr, warn.conflicts = FALSE) 20 | 21 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_impala()) 22 | lf \%>\% transmute(X = bitwNot(bitwOr(b, c))) 23 | } 24 | -------------------------------------------------------------------------------- /man/backend-mysql.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-mysql.R 3 | \name{backend-mysql} 4 | \alias{simulate_mysql} 5 | \alias{simulate_mariadb} 6 | \title{Backend: MySQL/MariaDB} 7 | \usage{ 8 | simulate_mysql() 9 | 10 | simulate_mariadb() 11 | } 12 | \description{ 13 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 14 | details of overall translation technology. Key differences for this backend 15 | are: 16 | \itemize{ 17 | \item \code{paste()} uses \code{CONCAT_WS()} 18 | \item String translations for \code{str_detect()}, \code{str_locate()}, and 19 | \code{str_replace_all()} 20 | \item Clear error message for unsupported full joins 21 | } 22 | 23 | Use \code{simulate_mysql()} with \code{lazy_frame()} to see simulated SQL without 24 | converting to live access database. 25 | } 26 | \examples{ 27 | library(dplyr, warn.conflicts = FALSE) 28 | 29 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_mysql()) 30 | lf \%>\% transmute(x = paste0(d, " times")) 31 | } 32 | -------------------------------------------------------------------------------- /man/backend-odbc.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-odbc.R 3 | \name{backend-odbc} 4 | \alias{simulate_odbc} 5 | \title{Backend: ODBC} 6 | \usage{ 7 | simulate_odbc() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are minor translations for common data types. 13 | 14 | Use \code{simulate_odbc()} with \code{lazy_frame()} to see simulated SQL without 15 | converting to live access database. 16 | } 17 | \examples{ 18 | library(dplyr, warn.conflicts = FALSE) 19 | 20 | lf <- lazy_frame(a = TRUE, b = 1, d = 2, c = "z", con = simulate_odbc()) 21 | lf \%>\% transmute(x = as.numeric(b)) 22 | lf \%>\% transmute(x = as.integer(b)) 23 | lf \%>\% transmute(x = as.character(b)) 24 | } 25 | -------------------------------------------------------------------------------- /man/backend-oracle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-oracle.R 3 | \name{backend-oracle} 4 | \alias{simulate_oracle} 5 | \title{Backend: Oracle} 6 | \usage{ 7 | simulate_oracle() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are: 13 | \itemize{ 14 | \item Use \verb{FETCH FIRST} instead of \code{LIMIT} 15 | \item Custom types 16 | \item \code{paste()} uses \code{||} 17 | \item Custom subquery generation (no \code{AS}) 18 | \item \code{setdiff()} uses \code{MINUS} instead of \code{EXCEPT} 19 | } 20 | 21 | Note that versions of Oracle prior to 23c have limited supported for 22 | \code{TRUE} and \code{FALSE} and you may need to use \code{1} and \code{0} instead. 23 | See \url{https://oracle-base.com/articles/23/boolean-data-type-23} for 24 | more details. 25 | 26 | Use \code{simulate_oracle()} with \code{lazy_frame()} to see simulated SQL without 27 | converting to live access database. 28 | } 29 | \examples{ 30 | library(dplyr, warn.conflicts = FALSE) 31 | 32 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_oracle()) 33 | lf \%>\% transmute(x = paste0(c, " times")) 34 | lf \%>\% setdiff(lf) 35 | } 36 | -------------------------------------------------------------------------------- /man/backend-postgres.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-postgres.R 3 | \name{backend-postgres} 4 | \alias{simulate_postgres} 5 | \title{Backend: PostgreSQL} 6 | \usage{ 7 | simulate_postgres() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are: 13 | \itemize{ 14 | \item Many stringr functions 15 | \item lubridate date-time extraction functions 16 | \item More standard statistical summaries 17 | } 18 | 19 | Use \code{simulate_postgres()} with \code{lazy_frame()} to see simulated SQL without 20 | converting to live access database. 21 | } 22 | \examples{ 23 | library(dplyr, warn.conflicts = FALSE) 24 | 25 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_postgres()) 26 | lf \%>\% summarise(x = sd(b, na.rm = TRUE)) 27 | lf \%>\% summarise(y = cor(b, c), z = cov(b, c)) 28 | } 29 | -------------------------------------------------------------------------------- /man/backend-redshift.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-redshift.R 3 | \name{backend-redshift} 4 | \alias{simulate_redshift} 5 | \title{Backend: Redshift} 6 | \usage{ 7 | simulate_redshift() 8 | } 9 | \description{ 10 | Base translations come from \link[=simulate_postgres]{PostgreSQL backend}. There 11 | are generally few differences, apart from string manipulation. 12 | 13 | Use \code{simulate_redshift()} with \code{lazy_frame()} to see simulated SQL without 14 | converting to live access database. 15 | } 16 | \examples{ 17 | library(dplyr, warn.conflicts = FALSE) 18 | 19 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_redshift()) 20 | lf \%>\% transmute(x = paste(c, " times")) 21 | lf \%>\% transmute(x = substr(c, 2, 3)) 22 | lf \%>\% transmute(x = str_replace_all(c, "a", "z")) 23 | } 24 | -------------------------------------------------------------------------------- /man/backend-snowflake.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-snowflake.R 3 | \name{backend-snowflake} 4 | \alias{simulate_snowflake} 5 | \title{Backend: Snowflake} 6 | \usage{ 7 | simulate_snowflake() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. 12 | 13 | Use \code{simulate_snowflake()} with \code{lazy_frame()} to see simulated SQL without 14 | converting to live access database. 15 | } 16 | \examples{ 17 | library(dplyr, warn.conflicts = FALSE) 18 | 19 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_snowflake()) 20 | lf \%>\% transmute(x = paste0(d, " times")) 21 | } 22 | -------------------------------------------------------------------------------- /man/backend-spark-sql.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-spark-sql.R 3 | \name{backend-spark-sql} 4 | \alias{simulate_spark_sql} 5 | \title{Backend: Databricks Spark SQL} 6 | \usage{ 7 | simulate_spark_sql() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are better translation of statistical aggregate functions 13 | (e.g. \code{var()}, \code{median()}) and use of temporary views instead of temporary 14 | tables when copying data. 15 | 16 | Use \code{simulate_spark_sql()} with \code{lazy_frame()} to see simulated SQL without 17 | converting to live access database. 18 | } 19 | \examples{ 20 | library(dplyr, warn.conflicts = FALSE) 21 | 22 | lf <- lazy_frame(a = TRUE, b = 1, d = 2, c = "z", con = simulate_spark_sql()) 23 | 24 | lf \%>\% summarise(x = median(d, na.rm = TRUE)) 25 | lf \%>\% summarise(x = var(c, na.rm = TRUE), .by = d) 26 | 27 | lf \%>\% mutate(x = first(c)) 28 | lf \%>\% mutate(x = first(c), .by = d) 29 | } 30 | -------------------------------------------------------------------------------- /man/backend-sqlite.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-sqlite.R 3 | \name{backend-sqlite} 4 | \alias{simulate_sqlite} 5 | \title{Backend: SQLite} 6 | \usage{ 7 | simulate_sqlite() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are: 13 | \itemize{ 14 | \item Uses non-standard \code{LOG()} function 15 | \item Date-time extraction functions from lubridate 16 | \item Custom median translation 17 | \item Right and full joins are simulated using left joins 18 | } 19 | 20 | Use \code{simulate_sqlite()} with \code{lazy_frame()} to see simulated SQL without 21 | converting to live access database. 22 | } 23 | \examples{ 24 | library(dplyr, warn.conflicts = FALSE) 25 | 26 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_sqlite()) 27 | lf \%>\% transmute(x = paste(c, " times")) 28 | lf \%>\% transmute(x = log(b), y = log(b, base = 2)) 29 | } 30 | -------------------------------------------------------------------------------- /man/backend-teradata.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/backend-teradata.R 3 | \name{backend-teradata} 4 | \alias{simulate_teradata} 5 | \title{Backend: Teradata} 6 | \usage{ 7 | simulate_teradata() 8 | } 9 | \description{ 10 | See \code{vignette("translation-function")} and \code{vignette("translation-verb")} for 11 | details of overall translation technology. Key differences for this backend 12 | are: 13 | \itemize{ 14 | \item Uses \code{TOP} instead of \code{LIMIT} 15 | \item Selection of user supplied translations 16 | } 17 | 18 | Use \code{simulate_teradata()} with \code{lazy_frame()} to see simulated SQL without 19 | converting to live access database. 20 | } 21 | \examples{ 22 | library(dplyr, warn.conflicts = FALSE) 23 | 24 | lf <- lazy_frame(a = TRUE, b = 1, c = 2, d = "z", con = simulate_teradata()) 25 | lf \%>\% head() 26 | } 27 | -------------------------------------------------------------------------------- /man/build_sql.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build-sql.R 3 | \name{build_sql} 4 | \alias{build_sql} 5 | \title{Build a SQL string.} 6 | \usage{ 7 | build_sql(..., .env = parent.frame(), con = sql_current_con()) 8 | } 9 | \arguments{ 10 | \item{...}{input to convert to SQL. Use \code{\link[=sql]{sql()}} to preserve 11 | user input as is (dangerous), and \code{\link[=ident]{ident()}} to label user 12 | input as sql identifiers (safe)} 13 | 14 | \item{.env}{the environment in which to evaluate the arguments. Should not 15 | be needed in typical use.} 16 | 17 | \item{con}{database connection; used to select correct quoting characters.} 18 | } 19 | \description{ 20 | This is a convenience function that should prevent sql injection attacks 21 | (which in the context of dplyr are most likely to be accidental not 22 | deliberate) by automatically escaping all expressions in the input, while 23 | treating bare strings as sql. This is unlikely to prevent any serious 24 | attack, but should make it unlikely that you produce invalid sql. 25 | } 26 | \details{ 27 | This function should be used only when generating \code{SELECT} clauses, 28 | other high level queries, or for other syntax that has no R equivalent. 29 | For individual function translations, prefer \code{\link[=sql_expr]{sql_expr()}}. 30 | } 31 | \examples{ 32 | con <- simulate_dbi() 33 | build_sql("SELECT * FROM TABLE", con = con) 34 | x <- "TABLE" 35 | build_sql("SELECT * FROM ", x, con = con) 36 | build_sql("SELECT * FROM ", ident(x), con = con) 37 | build_sql("SELECT * FROM ", sql(x), con = con) 38 | 39 | # http://xkcd.com/327/ 40 | name <- "Robert'); DROP TABLE Students;--" 41 | build_sql("INSERT INTO Students (Name) VALUES (", name, ")", con = con) 42 | } 43 | \keyword{internal} 44 | -------------------------------------------------------------------------------- /man/complete.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-expand.R 3 | \name{complete.tbl_lazy} 4 | \alias{complete.tbl_lazy} 5 | \title{Complete a SQL table with missing combinations of data} 6 | \usage{ 7 | \method{complete}{tbl_lazy}(data, ..., fill = list()) 8 | } 9 | \arguments{ 10 | \item{data}{A lazy data frame backed by a database query.} 11 | 12 | \item{...}{Specification of columns to expand. See \link[tidyr:expand]{tidyr::expand} for 13 | more details.} 14 | 15 | \item{fill}{A named list that for each variable supplies a single value to 16 | use instead of NA for missing combinations.} 17 | } 18 | \value{ 19 | Another \code{tbl_lazy}. Use \code{\link[=show_query]{show_query()}} to see the generated 20 | query, and use \code{\link[=collect.tbl_sql]{collect()}} to execute the query 21 | and return data to R. 22 | } 23 | \description{ 24 | Turns implicit missing values into explicit missing values. This is a method 25 | for the \code{\link[tidyr:complete]{tidyr::complete()}} generic. 26 | } 27 | \examples{ 28 | \dontshow{if (rlang::is_installed("tidyr", version = "1.0.0")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 29 | df <- memdb_frame( 30 | group = c(1:2, 1), 31 | item_id = c(1:2, 2), 32 | item_name = c("a", "b", "b"), 33 | value1 = 1:3, 34 | value2 = 4:6 35 | ) 36 | 37 | df \%>\% tidyr::complete(group, nesting(item_id, item_name)) 38 | 39 | # You can also choose to fill in missing values 40 | df \%>\% tidyr::complete(group, nesting(item_id, item_name), fill = list(value1 = 0)) 41 | \dontshow{\}) # examplesIf} 42 | } 43 | -------------------------------------------------------------------------------- /man/copy_inline.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-copy-to.R 3 | \name{copy_inline} 4 | \alias{copy_inline} 5 | \title{Use a local data frame in a dbplyr query} 6 | \usage{ 7 | copy_inline(con, df, types = NULL) 8 | } 9 | \arguments{ 10 | \item{con}{A database connection.} 11 | 12 | \item{df}{A local data frame. The data is written directly in the SQL query 13 | so it should be small.} 14 | 15 | \item{types}{A named character vector of SQL data types to use for the columns. 16 | The data types are backend specific. For example for Postgres this could 17 | be \code{c(id = "bigint", created_at = "timestamp", values = "integer[]")}. 18 | If \code{NULL}, the default, the types are determined from \code{df}.} 19 | } 20 | \value{ 21 | A \code{tbl_lazy}. 22 | } 23 | \description{ 24 | This is an alternative to \code{\link[=copy_to]{copy_to()}} that does not need write access and 25 | is faster for small data. 26 | } 27 | \details{ 28 | It writes the data directly in the SQL query via the \code{VALUES} clause. 29 | } 30 | \examples{ 31 | df <- data.frame(x = 1:3, y = c("a", "b", "c")) 32 | con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:") 33 | 34 | copy_inline(con, df) 35 | 36 | copy_inline(con, df) \%>\% dplyr::show_query() 37 | } 38 | \seealso{ 39 | \code{\link[=copy_to]{copy_to()}} to copy the data into a new database table. 40 | } 41 | -------------------------------------------------------------------------------- /man/db-misc.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db.R 3 | \name{db-misc} 4 | \alias{db_connection_describe} 5 | \alias{sql_join_suffix} 6 | \alias{db_sql_render} 7 | \alias{db_col_types} 8 | \alias{dbplyr_edition} 9 | \title{Miscellaneous database generics} 10 | \usage{ 11 | db_connection_describe(con, ...) 12 | 13 | sql_join_suffix(con, suffix, ...) 14 | 15 | db_sql_render(con, sql, ..., cte = FALSE, sql_options = NULL) 16 | 17 | db_col_types(con, table, call) 18 | 19 | dbplyr_edition(con) 20 | } 21 | \description{ 22 | \itemize{ 23 | \item \code{db_connection_describe()} provides a short string describing the 24 | database connection, helping users tell which database a table comes 25 | from. It should be a single line, and ideally less than 60 characters wide. 26 | } 27 | } 28 | \details{ 29 | \itemize{ 30 | \item \code{dbplyr_edition()} declares which version of the dbplyr API you want. 31 | See below for more details. 32 | \item \code{db_col_types()} returns the column types of a table. 33 | } 34 | } 35 | \section{dbplyr 2.0.0}{ 36 | 37 | dbplyr 2.0.0 renamed a number of generics so that they could be cleanly moved 38 | from dplyr to dbplyr. If you have an existing backend, you'll need to rename 39 | the following methods. 40 | \itemize{ 41 | \item \code{dplyr::db_desc()} -> \code{dbplyr::db_connection_describe()} (also note that 42 | the argument named changed from \code{x} to \code{con}). 43 | } 44 | } 45 | 46 | \seealso{ 47 | Other generic: 48 | \code{\link{db-sql}}, 49 | \code{\link{db_copy_to}()}, 50 | \code{\link{sql_escape_logical}()} 51 | } 52 | \concept{generic} 53 | \keyword{internal} 54 | -------------------------------------------------------------------------------- /man/db-quote.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db-escape.R 3 | \name{db-quote} 4 | \alias{sql_escape_logical} 5 | \alias{sql_escape_date} 6 | \alias{sql_escape_datetime} 7 | \alias{sql_escape_raw} 8 | \title{SQL escaping/quoting generics} 9 | \usage{ 10 | sql_escape_logical(con, x) 11 | 12 | sql_escape_date(con, x) 13 | 14 | sql_escape_datetime(con, x) 15 | 16 | sql_escape_raw(con, x) 17 | } 18 | \description{ 19 | These generics translate individual values into SQL. The core 20 | generics are \code{\link[DBI:dbQuoteIdentifier]{DBI::dbQuoteIdentifier()}} and \link[DBI:dbQuoteString]{DBI::dbQuoteString} 21 | for quoting identifiers and strings, but dbplyr needs additional 22 | tools for inserting logical, date, date-time, and raw values into 23 | queries. 24 | } 25 | \examples{ 26 | con <- simulate_dbi() 27 | sql_escape_logical(con, c(TRUE, FALSE, NA)) 28 | sql_escape_date(con, Sys.Date()) 29 | sql_escape_date(con, Sys.time()) 30 | sql_escape_raw(con, charToRaw("hi")) 31 | } 32 | \seealso{ 33 | Other generic: 34 | \code{\link{db-sql}}, 35 | \code{\link{db_connection_describe}()}, 36 | \code{\link{db_copy_to}()} 37 | } 38 | \concept{generic} 39 | \keyword{internal} 40 | -------------------------------------------------------------------------------- /man/dbplyr-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dbplyr.R 3 | \docType{package} 4 | \name{dbplyr-package} 5 | \alias{dbplyr} 6 | \alias{dbplyr-package} 7 | \title{dbplyr: A 'dplyr' Back End for Databases} 8 | \description{ 9 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 10 | 11 | A 'dplyr' back end for databases that allows you to work with remote database tables as if they are in-memory data frames. Basic features works with any database that has a 'DBI' back end; more advanced features require 'SQL' translation to be provided by the package author. 12 | } 13 | \seealso{ 14 | Useful links: 15 | \itemize{ 16 | \item \url{https://dbplyr.tidyverse.org/} 17 | \item \url{https://github.com/tidyverse/dbplyr} 18 | \item Report bugs at \url{https://github.com/tidyverse/dbplyr/issues} 19 | } 20 | 21 | } 22 | \author{ 23 | \strong{Maintainer}: Hadley Wickham \email{hadley@posit.co} 24 | 25 | Authors: 26 | \itemize{ 27 | \item Maximilian Girlich 28 | \item Edgar Ruiz 29 | } 30 | 31 | Other contributors: 32 | \itemize{ 33 | \item Posit Software, PBC [copyright holder, funder] 34 | } 35 | 36 | } 37 | \keyword{internal} 38 | -------------------------------------------------------------------------------- /man/dbplyr_uncount.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-uncount.R 3 | \name{dbplyr_uncount} 4 | \alias{dbplyr_uncount} 5 | \title{"Uncount" a database table} 6 | \usage{ 7 | dbplyr_uncount(data, weights, .remove = TRUE, .id = NULL) 8 | } 9 | \arguments{ 10 | \item{data}{A lazy data frame backed by a database query.} 11 | 12 | \item{weights}{A vector of weights. Evaluated in the context of \code{data}; 13 | supports quasiquotation.} 14 | 15 | \item{.remove}{If \code{TRUE}, and \code{weights} is the name of a column in \code{data}, 16 | then this column is removed.} 17 | 18 | \item{.id}{Supply a string to create a new variable which gives a unique 19 | identifier for each created row.} 20 | } 21 | \description{ 22 | This is a method for the tidyr \code{uncount()} generic. It uses a temporary 23 | table, so your database user needs permissions to create one. 24 | } 25 | \examples{ 26 | df <- memdb_frame(x = c("a", "b"), n = c(1, 2)) 27 | dbplyr_uncount(df, n) 28 | dbplyr_uncount(df, n, .id = "id") 29 | 30 | # You can also use constants 31 | dbplyr_uncount(df, 2) 32 | 33 | # Or expressions 34 | dbplyr_uncount(df, 2 / n) 35 | } 36 | -------------------------------------------------------------------------------- /man/distinct.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-distinct.R 3 | \name{distinct.tbl_lazy} 4 | \alias{distinct.tbl_lazy} 5 | \title{Subset distinct/unique rows} 6 | \usage{ 7 | \method{distinct}{tbl_lazy}(.data, ..., .keep_all = FALSE) 8 | } 9 | \arguments{ 10 | \item{.data}{A lazy data frame backed by a database query.} 11 | 12 | \item{...}{<\code{\link[rlang:args_data_masking]{data-masking}}> Variables, or 13 | functions of variables. Use \code{\link[dplyr:desc]{desc()}} to sort a variable in descending 14 | order.} 15 | 16 | \item{.keep_all}{If \code{TRUE}, keep all variables in \code{.data}. 17 | If a combination of \code{...} is not distinct, this keeps the 18 | first row of values.} 19 | } 20 | \value{ 21 | Another \code{tbl_lazy}. Use \code{\link[=show_query]{show_query()}} to see the generated 22 | query, and use \code{\link[=collect.tbl_sql]{collect()}} to execute the query 23 | and return data to R. 24 | } 25 | \description{ 26 | This is a method for the dplyr \code{\link[=distinct]{distinct()}} generic. It adds the 27 | \code{DISTINCT} clause to the SQL query. 28 | } 29 | \examples{ 30 | library(dplyr, warn.conflicts = FALSE) 31 | 32 | db <- memdb_frame(x = c(1, 1, 2, 2), y = c(1, 2, 1, 1)) 33 | db \%>\% distinct() \%>\% show_query() 34 | db \%>\% distinct(x) \%>\% show_query() 35 | } 36 | -------------------------------------------------------------------------------- /man/do.tbl_sql.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-do.R 3 | \name{do.tbl_sql} 4 | \alias{do.tbl_sql} 5 | \title{Perform arbitrary computation on remote backend} 6 | \usage{ 7 | \method{do}{tbl_sql}(.data, ..., .chunk_size = 10000L) 8 | } 9 | \arguments{ 10 | \item{.data}{a tbl} 11 | 12 | \item{...}{Expressions to apply to each group. If named, results will be 13 | stored in a new column. If unnamed, must return a data frame. You can 14 | use \code{.} to refer to the current group. You can not mix named and 15 | unnamed arguments.} 16 | 17 | \item{.chunk_size}{The size of each chunk to pull into R. If this number is 18 | too big, the process will be slow because R has to allocate and free a lot 19 | of memory. If it's too small, it will be slow, because of the overhead of 20 | talking to the database.} 21 | } 22 | \description{ 23 | Perform arbitrary computation on remote backend 24 | } 25 | -------------------------------------------------------------------------------- /man/escape.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/escape.R 3 | \name{escape} 4 | \alias{escape} 5 | \alias{escape_ansi} 6 | \alias{sql_vector} 7 | \title{Escape/quote a string.} 8 | \usage{ 9 | escape(x, parens = NA, collapse = " ", con = NULL) 10 | 11 | escape_ansi(x, parens = NA, collapse = "") 12 | 13 | sql_vector(x, parens = NA, collapse = " ", con = NULL) 14 | } 15 | \arguments{ 16 | \item{x}{An object to escape. Existing sql vectors will be left as is, 17 | character vectors are escaped with single quotes, numeric vectors have 18 | trailing \code{.0} added if they're whole numbers, identifiers are 19 | escaped with double quotes.} 20 | 21 | \item{parens, collapse}{Controls behaviour when multiple values are supplied. 22 | \code{parens} should be a logical flag, or if \code{NA}, will wrap in 23 | parens if length > 1. 24 | 25 | Default behaviour: lists are always wrapped in parens and separated by 26 | commas, identifiers are separated by commas and never wrapped, 27 | atomic vectors are separated by spaces and wrapped in parens if needed.} 28 | 29 | \item{con}{Database connection.} 30 | } 31 | \description{ 32 | \code{escape()} requires you to provide a database connection to control the 33 | details of escaping. \code{escape_ansi()} uses the SQL 92 ANSI standard. 34 | } 35 | \examples{ 36 | # Doubles vs. integers 37 | escape_ansi(1:5) 38 | escape_ansi(c(1, 5.4)) 39 | 40 | # String vs known sql vs. sql identifier 41 | escape_ansi("X") 42 | escape_ansi(sql("X")) 43 | escape_ansi(ident("X")) 44 | 45 | # Escaping is idempotent 46 | escape_ansi("X") 47 | escape_ansi(escape_ansi("X")) 48 | escape_ansi(escape_ansi(escape_ansi("X"))) 49 | } 50 | -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: archived 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | archived 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: defunct 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | defunct 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: experimental 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | experimental 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: maturing 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | maturing 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: questioning 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | questioning 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: soft-deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | soft-deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: stable 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | lifecycle 21 | 22 | 25 | 26 | stable 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: superseded 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | superseded 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/man/figures/logo.png -------------------------------------------------------------------------------- /man/fill.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-fill.R 3 | \name{fill.tbl_lazy} 4 | \alias{fill.tbl_lazy} 5 | \title{Fill in missing values with previous or next value} 6 | \usage{ 7 | \method{fill}{tbl_lazy}(.data, ..., .direction = c("down", "up", "updown", "downup")) 8 | } 9 | \arguments{ 10 | \item{.data}{A lazy data frame backed by a database query.} 11 | 12 | \item{...}{Columns to fill.} 13 | 14 | \item{.direction}{Direction in which to fill missing values. Currently 15 | either "down" (the default) or "up". Note that "up" does not work when 16 | \code{.data} is sorted by non-numeric columns. As a workaround revert the order 17 | yourself beforehand; for example replace \code{arrange(x, desc(y))} by 18 | \code{arrange(desc(x), y)}.} 19 | } 20 | \description{ 21 | Fill in missing values with previous or next value 22 | } 23 | \examples{ 24 | \dontshow{if (rlang::is_installed("tidyr", version = "1.0.0")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 25 | squirrels <- tibble::tribble( 26 | ~group, ~name, ~role, ~n_squirrels, ~ n_squirrels2, 27 | 1, "Sam", "Observer", NA, 1, 28 | 1, "Mara", "Scorekeeper", 8, NA, 29 | 1, "Jesse", "Observer", NA, NA, 30 | 1, "Tom", "Observer", NA, 4, 31 | 2, "Mike", "Observer", NA, NA, 32 | 2, "Rachael", "Observer", NA, 6, 33 | 2, "Sydekea", "Scorekeeper", 14, NA, 34 | 2, "Gabriela", "Observer", NA, NA, 35 | 3, "Derrick", "Observer", NA, NA, 36 | 3, "Kara", "Scorekeeper", 9, 10, 37 | 3, "Emily", "Observer", NA, NA, 38 | 3, "Danielle", "Observer", NA, NA 39 | ) 40 | squirrels$id <- 1:12 41 | 42 | tbl_memdb(squirrels) \%>\% 43 | window_order(id) \%>\% 44 | tidyr::fill( 45 | n_squirrels, 46 | n_squirrels2, 47 | ) 48 | \dontshow{\}) # examplesIf} 49 | } 50 | -------------------------------------------------------------------------------- /man/filter.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-filter.R 3 | \name{filter.tbl_lazy} 4 | \alias{filter.tbl_lazy} 5 | \title{Subset rows using column values} 6 | \usage{ 7 | \method{filter}{tbl_lazy}(.data, ..., .by = NULL, .preserve = FALSE) 8 | } 9 | \arguments{ 10 | \item{.data}{A lazy data frame backed by a database query.} 11 | 12 | \item{...}{<\code{\link[rlang:args_data_masking]{data-masking}}> Variables, or 13 | functions of variables. Use \code{\link[dplyr:desc]{desc()}} to sort a variable in descending 14 | order.} 15 | 16 | \item{.by}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 17 | 18 | <\code{\link[dplyr:dplyr_tidy_select]{tidy-select}}> Optionally, a selection of columns to 19 | group by for just this operation, functioning as an alternative to \code{\link[dplyr:group_by]{group_by()}}. For 20 | details and examples, see \link[dplyr:dplyr_by]{?dplyr_by}.} 21 | 22 | \item{.preserve}{Not supported by this method.} 23 | } 24 | \value{ 25 | Another \code{tbl_lazy}. Use \code{\link[=show_query]{show_query()}} to see the generated 26 | query, and use \code{\link[=collect.tbl_sql]{collect()}} to execute the query 27 | and return data to R. 28 | } 29 | \description{ 30 | This is a method for the dplyr \code{\link[=filter]{filter()}} generic. It generates the 31 | \code{WHERE} clause of the SQL query. 32 | } 33 | \examples{ 34 | library(dplyr, warn.conflicts = FALSE) 35 | 36 | db <- memdb_frame(x = c(2, NA, 5, NA, 10), y = 1:5) 37 | db \%>\% filter(x < 5) \%>\% show_query() 38 | db \%>\% filter(is.na(x)) \%>\% show_query() 39 | } 40 | -------------------------------------------------------------------------------- /man/get_returned_rows.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rows.R 3 | \name{get_returned_rows} 4 | \alias{get_returned_rows} 5 | \alias{has_returned_rows} 6 | \title{Extract and check the \code{RETURNING} rows} 7 | \usage{ 8 | get_returned_rows(x) 9 | 10 | has_returned_rows(x) 11 | } 12 | \arguments{ 13 | \item{x}{A lazy tbl.} 14 | } 15 | \value{ 16 | For \code{get_returned_rows()}, a tibble. 17 | 18 | For \code{has_returned_rows()}, a scalar logical. 19 | } 20 | \description{ 21 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 22 | 23 | \code{get_returned_rows()} extracts the \code{RETURNING} rows produced by 24 | \code{\link[=rows_insert]{rows_insert()}}, \code{\link[=rows_append]{rows_append()}}, \code{\link[=rows_update]{rows_update()}}, \code{\link[=rows_upsert]{rows_upsert()}}, 25 | or \code{\link[=rows_delete]{rows_delete()}} if these are called with the \code{returning} argument. 26 | An error is raised if this information is not available. 27 | 28 | \code{has_returned_rows()} checks if \code{x} has stored RETURNING rows produced by 29 | \code{\link[=rows_insert]{rows_insert()}}, \code{\link[=rows_append]{rows_append()}}, \code{\link[=rows_update]{rows_update()}}, \code{\link[=rows_upsert]{rows_upsert()}}, 30 | or \code{\link[=rows_delete]{rows_delete()}}. 31 | } 32 | \examples{ 33 | library(dplyr) 34 | 35 | con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:") 36 | DBI::dbExecute(con, "CREATE TABLE Info ( 37 | id INTEGER PRIMARY KEY AUTOINCREMENT, 38 | number INTEGER 39 | )") 40 | info <- tbl(con, "Info") 41 | 42 | rows1 <- copy_inline(con, data.frame(number = c(1, 5))) 43 | rows_insert(info, rows1, conflict = "ignore", in_place = TRUE) 44 | info 45 | 46 | # If the table has an auto incrementing primary key, you can use 47 | # the returning argument + `get_returned_rows()` its value 48 | rows2 <- copy_inline(con, data.frame(number = c(13, 27))) 49 | info <- rows_insert( 50 | info, 51 | rows2, 52 | conflict = "ignore", 53 | in_place = TRUE, 54 | returning = id 55 | ) 56 | info 57 | get_returned_rows(info) 58 | } 59 | -------------------------------------------------------------------------------- /man/group_by.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-group_by.R 3 | \name{group_by.tbl_lazy} 4 | \alias{group_by.tbl_lazy} 5 | \title{Group by one or more variables} 6 | \usage{ 7 | \method{group_by}{tbl_lazy}(.data, ..., .add = FALSE, add = deprecated(), .drop = TRUE) 8 | } 9 | \arguments{ 10 | \item{.data}{A lazy data frame backed by a database query.} 11 | 12 | \item{...}{<\code{\link[rlang:args_data_masking]{data-masking}}> Variables, or 13 | functions of variables. Use \code{\link[dplyr:desc]{desc()}} to sort a variable in descending 14 | order.} 15 | 16 | \item{.add}{When \code{FALSE}, the default, \code{group_by()} will 17 | override existing groups. To add to the existing groups, use 18 | \code{.add = TRUE}. 19 | 20 | This argument was previously called \code{add}, but that prevented 21 | creating a new grouping variable called \code{add}, and conflicts with 22 | our naming conventions.} 23 | 24 | \item{add}{Deprecated. Please use \code{.add} instead.} 25 | 26 | \item{.drop}{Not supported by this method.} 27 | } 28 | \description{ 29 | This is a method for the dplyr \code{\link[=group_by]{group_by()}} generic. It is translated to 30 | the \verb{GROUP BY} clause of the SQL query when used with 31 | \code{\link[=summarise.tbl_lazy]{summarise()}} and to the \verb{PARTITION BY} clause of 32 | window functions when used with \code{\link[=mutate.tbl_lazy]{mutate()}}. 33 | } 34 | \examples{ 35 | library(dplyr, warn.conflicts = FALSE) 36 | 37 | db <- memdb_frame(g = c(1, 1, 1, 2, 2), x = c(4, 3, 6, 9, 2)) 38 | db \%>\% 39 | group_by(g) \%>\% 40 | summarise(n()) \%>\% 41 | show_query() 42 | 43 | db \%>\% 44 | group_by(g) \%>\% 45 | mutate(x2 = x / sum(x, na.rm = TRUE)) \%>\% 46 | show_query() 47 | } 48 | -------------------------------------------------------------------------------- /man/head.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-head.R 3 | \name{head.tbl_lazy} 4 | \alias{head.tbl_lazy} 5 | \title{Subset the first rows} 6 | \usage{ 7 | \method{head}{tbl_lazy}(x, n = 6L, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A lazy data frame backed by a database query.} 11 | 12 | \item{n}{Number of rows to return} 13 | 14 | \item{...}{Not used.} 15 | } 16 | \value{ 17 | Another \code{tbl_lazy}. Use \code{\link[=show_query]{show_query()}} to see the generated 18 | query, and use \code{\link[=collect.tbl_sql]{collect()}} to execute the query 19 | and return data to R. 20 | } 21 | \description{ 22 | This is a method for the \code{\link[=head]{head()}} generic. It is usually translated to the 23 | \code{LIMIT} clause of the SQL query. Because \code{LIMIT} is not an official part of 24 | the SQL specification, some database use other clauses like \code{TOP} or 25 | \verb{FETCH ROWS}. 26 | 27 | Note that databases don't really have a sense of row order, so what "first" 28 | means is subject to interpretation. Most databases will respect ordering 29 | performed with \code{arrange()}, but it's not guaranteed. \code{tail()} is not 30 | supported at all because the situation is even murkier for the "last" rows. 31 | } 32 | \examples{ 33 | library(dplyr, warn.conflicts = FALSE) 34 | 35 | db <- memdb_frame(x = 1:100) 36 | db \%>\% head() \%>\% show_query() 37 | 38 | # Pretend we have data in a SQL server database 39 | db2 <- lazy_frame(x = 1:100, con = simulate_mssql()) 40 | db2 \%>\% head() \%>\% show_query() 41 | } 42 | -------------------------------------------------------------------------------- /man/ident.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ident.R 3 | \name{ident} 4 | \alias{ident} 5 | \alias{is.ident} 6 | \title{Flag a character vector as SQL identifiers} 7 | \usage{ 8 | ident(...) 9 | 10 | is.ident(x) 11 | } 12 | \arguments{ 13 | \item{...}{A character vector, or name-value pairs.} 14 | 15 | \item{x}{An object.} 16 | } 17 | \description{ 18 | \code{ident()} takes strings and turns them as database identifiers (e.g. table 19 | or column names) quoting them using the identifer rules for your database. 20 | \code{ident_q()} does the same, but assumes the names have already been 21 | quoted, preventing them from being quoted again. 22 | 23 | These are generally for internal use only; if you need to supply an 24 | table name that is qualified with schema or catalog, or has already been 25 | quoted for some other reason, use \code{I()}. 26 | } 27 | \examples{ 28 | # SQL92 quotes strings with ' 29 | escape_ansi("x") 30 | 31 | # And identifiers with " 32 | ident("x") 33 | escape_ansi(ident("x")) 34 | 35 | # You can supply multiple inputs 36 | ident(a = "x", b = "y") 37 | ident_q(a = "x", b = "y") 38 | } 39 | \keyword{internal} 40 | -------------------------------------------------------------------------------- /man/ident_q.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/schema.R 3 | \name{ident_q} 4 | \alias{ident_q} 5 | \title{Declare a identifier as being pre-quoted.} 6 | \usage{ 7 | ident_q(...) 8 | } 9 | \description{ 10 | No longer needed; please use \code{\link[=sql]{sql()}} instead. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/in_schema.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/schema.R 3 | \name{in_schema} 4 | \alias{in_schema} 5 | \alias{in_catalog} 6 | \title{Refer to a table in another schema/catalog} 7 | \usage{ 8 | in_schema(schema, table) 9 | 10 | in_catalog(catalog, schema, table) 11 | } 12 | \arguments{ 13 | \item{catalog, schema, table}{Names of catalog, schema, and table. 14 | These will be automatically quoted; use \code{\link[=sql]{sql()}} to pass a raw name 15 | that won't get quoted.} 16 | } 17 | \description{ 18 | \code{in_schema()} and \code{in_catalog()} can be used to refer to tables outside of 19 | the current catalog/schema. However, we now recommend using \code{I()} as it's 20 | typically less typing. 21 | } 22 | \examples{ 23 | # Previously: 24 | in_schema("my_schema", "my_table") 25 | in_catalog("my_catalog", "my_schema", "my_table") 26 | in_schema(sql("my_schema"), sql("my_table")) 27 | 28 | # Now 29 | I("my_schema.my_table") 30 | I("my_catalog.my_schema.my_table") 31 | I("my_schema.my_table") 32 | 33 | # Example using schemas with SQLite 34 | con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:") 35 | 36 | # Add auxiliary schema 37 | tmp <- tempfile() 38 | DBI::dbExecute(con, paste0("ATTACH '", tmp, "' AS aux")) 39 | 40 | library(dplyr, warn.conflicts = FALSE) 41 | copy_to(con, iris, "df", temporary = FALSE) 42 | copy_to(con, mtcars, I("aux.df"), temporary = FALSE) 43 | 44 | con \%>\% tbl("df") 45 | con \%>\% tbl(I("aux.df")) 46 | } 47 | \keyword{internal} 48 | -------------------------------------------------------------------------------- /man/intersect.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-set-ops.R 3 | \name{intersect.tbl_lazy} 4 | \alias{intersect.tbl_lazy} 5 | \alias{union.tbl_lazy} 6 | \alias{union_all.tbl_lazy} 7 | \alias{setdiff.tbl_lazy} 8 | \title{SQL set operations} 9 | \usage{ 10 | \method{intersect}{tbl_lazy}(x, y, copy = FALSE, ..., all = FALSE) 11 | 12 | \method{union}{tbl_lazy}(x, y, copy = FALSE, ..., all = FALSE) 13 | 14 | \method{union_all}{tbl_lazy}(x, y, copy = FALSE, ...) 15 | 16 | \method{setdiff}{tbl_lazy}(x, y, copy = FALSE, ..., all = FALSE) 17 | } 18 | \arguments{ 19 | \item{x, y}{A pair of lazy data frames backed by database queries.} 20 | 21 | \item{copy}{If \code{x} and \code{y} are not from the same data source, 22 | and \code{copy} is \code{TRUE}, then \code{y} will be copied into a 23 | temporary table in same database as \code{x}. \verb{*_join()} will automatically 24 | run \code{ANALYZE} on the created table in the hope that this will make 25 | you queries as efficient as possible by giving more data to the query 26 | planner. 27 | 28 | This allows you to join tables across srcs, but it's potentially expensive 29 | operation so you must opt into it.} 30 | 31 | \item{...}{Not currently used; provided for future extensions.} 32 | 33 | \item{all}{If \code{TRUE}, includes all matches in output, not just unique rows.} 34 | } 35 | \description{ 36 | These are methods for the dplyr generics \code{dplyr::intersect()}, 37 | \code{dplyr::union()}, and \code{dplyr::setdiff()}. They are translated to 38 | \code{INTERSECT}, \code{UNION}, and \code{EXCEPT} respectively. 39 | } 40 | -------------------------------------------------------------------------------- /man/is_table_path.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/table-name.R 3 | \name{is_table_path} 4 | \alias{is_table_path} 5 | \alias{table_path_name} 6 | \alias{table_path_components} 7 | \alias{check_table_path} 8 | \alias{as_table_path} 9 | \title{Table paths} 10 | \usage{ 11 | is_table_path(x) 12 | 13 | table_path_name(x, con) 14 | 15 | table_path_components(x, con) 16 | 17 | check_table_path(x, error_arg = caller_arg(x), error_call = caller_env()) 18 | 19 | as_table_path(x, con, error_arg = caller_arg(x), error_call = caller_env()) 20 | } 21 | \description{ 22 | dbplyr standardises all the ways of referring to a table (i.e. a single 23 | string, a string wrapped in \code{I()}, a \code{\link[DBI:Id]{DBI::Id()}} and the results of 24 | \code{\link[=in_schema]{in_schema()}} and \code{\link[=in_catalog]{in_catalog()}}) into a table "path" of the form 25 | \code{table}, \code{schema.table}, or \code{catalog.schema.path}. A table path is 26 | always suitable for inlining into a query, so user input is quoted unless 27 | it is wrapped in \code{I()}. 28 | 29 | This is primarily for internal usage, but you may need to work with it if 30 | you're implementing a backend, and you need to compute with the table path, 31 | not just pass it on unchanged to some other dbplyr function. 32 | \itemize{ 33 | \item \code{is_table_path()} returns \code{TRUE} if the object is a \code{table_path}. 34 | \item \code{as_table_path()} coerces known table identifiers to a \code{table_path}. 35 | \item \code{check_table_path()} throws an error if the object is not a \code{table_path}. 36 | \item \code{table_path_name()} returns the last component of the table path (i.e. 37 | the name of the table). 38 | \item \code{table_path_components()} returns a list containing the components of each 39 | table path. 40 | } 41 | 42 | A \code{table_path} object can technically be a vector of table paths, but 43 | you will never see this in table paths constructed from user inputs. 44 | } 45 | \keyword{internal} 46 | -------------------------------------------------------------------------------- /man/lahman.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data-lahman.R 3 | \name{lahman} 4 | \alias{lahman} 5 | \alias{lahman_sqlite} 6 | \alias{lahman_postgres} 7 | \alias{lahman_mysql} 8 | \alias{copy_lahman} 9 | \alias{has_lahman} 10 | \alias{lahman_srcs} 11 | \title{Cache and retrieve an \code{src_sqlite} of the Lahman baseball database.} 12 | \usage{ 13 | lahman_sqlite(path = NULL) 14 | 15 | lahman_postgres(dbname = "lahman", host = "localhost", ...) 16 | 17 | lahman_mysql(dbname = "lahman", ...) 18 | 19 | copy_lahman(con, ...) 20 | 21 | has_lahman(type, ...) 22 | 23 | lahman_srcs(..., quiet = NULL) 24 | } 25 | \arguments{ 26 | \item{...}{Other arguments passed to \code{src} on first 27 | load. For MySQL and PostgreSQL, the defaults assume you have a local 28 | server with \code{lahman} database already created. 29 | For \code{lahman_srcs()}, character vector of names giving srcs to generate.} 30 | 31 | \item{type}{src type.} 32 | 33 | \item{quiet}{if \code{TRUE}, suppress messages about databases failing to 34 | connect.} 35 | } 36 | \description{ 37 | This creates an interesting database using data from the Lahman baseball 38 | data source, provided by \href{http://seanlahman.com}{Sean Lahman}, and 39 | made easily available in R through the \pkg{Lahman} package by 40 | Michael Friendly, Dennis Murphy and Martin Monkman. See the documentation 41 | for that package for documentation of the individual tables. 42 | } 43 | \examples{ 44 | # Connect to a local sqlite database, if already created 45 | \donttest{ 46 | library(dplyr) 47 | 48 | if (has_lahman("sqlite")) { 49 | lahman_sqlite() 50 | batting <- tbl(lahman_sqlite(), "Batting") 51 | batting 52 | } 53 | 54 | # Connect to a local postgres database with lahman database, if available 55 | if (has_lahman("postgres")) { 56 | lahman_postgres() 57 | batting <- tbl(lahman_postgres(), "Batting") 58 | } 59 | } 60 | } 61 | \keyword{internal} 62 | -------------------------------------------------------------------------------- /man/lazy_ops.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/lazy-ops.R 3 | \name{lazy_ops} 4 | \alias{lazy_ops} 5 | \alias{lazy_base_query} 6 | \alias{op_grps} 7 | \alias{op_vars} 8 | \alias{op_sort} 9 | \alias{op_frame} 10 | \title{Lazy operations} 11 | \usage{ 12 | lazy_base_query(x, vars, class = character(), ...) 13 | 14 | op_grps(op) 15 | 16 | op_vars(op) 17 | 18 | op_sort(op) 19 | 20 | op_frame(op) 21 | } 22 | \description{ 23 | This set of S3 classes describe the action of dplyr verbs. These are 24 | currently used for SQL sources to separate the description of operations 25 | in R from their computation in SQL. This API is very new so is likely 26 | to evolve in the future. 27 | } 28 | \details{ 29 | \code{op_vars()} and \code{op_grps()} compute the variables and groups from 30 | a sequence of lazy operations. \code{op_sort()} and \code{op_frame()} tracks the 31 | order and frame for use in window functions. 32 | } 33 | \keyword{internal} 34 | -------------------------------------------------------------------------------- /man/memdb_frame.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/memdb.R 3 | \name{memdb_frame} 4 | \alias{memdb_frame} 5 | \alias{tbl_memdb} 6 | \alias{src_memdb} 7 | \title{Create a database table in temporary in-memory database.} 8 | \usage{ 9 | memdb_frame(..., .name = unique_table_name()) 10 | 11 | tbl_memdb(df, name = deparse(substitute(df))) 12 | 13 | src_memdb() 14 | } 15 | \arguments{ 16 | \item{...}{<\code{\link[rlang:dyn-dots]{dynamic-dots}}> 17 | A set of name-value pairs. These arguments are 18 | processed with \code{\link[rlang:defusing-advanced]{rlang::quos()}} and support unquote via \code{\link{!!}} and 19 | unquote-splice via \code{\link{!!!}}. Use \verb{:=} to create columns that start with a dot. 20 | 21 | Arguments are evaluated sequentially. 22 | You can refer to previously created elements directly or using the \link{.data} 23 | pronoun. 24 | To refer explicitly to objects in the calling environment, use \code{\link{!!}} or 25 | \link{.env}, e.g. \code{!!.data} or \code{.env$.data} for the special case of an object 26 | named \code{.data}.} 27 | 28 | \item{df}{Data frame to copy} 29 | 30 | \item{name, .name}{Name of table in database: defaults to a random name that's 31 | unlikely to conflict with an existing table.} 32 | } 33 | \description{ 34 | \code{memdb_frame()} works like \code{\link[tibble:tibble]{tibble::tibble()}}, but instead of creating a new 35 | data frame in R, it creates a table in \code{\link[=src_memdb]{src_memdb()}}. 36 | } 37 | \examples{ 38 | library(dplyr) 39 | df <- memdb_frame(x = runif(100), y = runif(100)) 40 | df \%>\% arrange(x) 41 | df \%>\% arrange(x) \%>\% show_query() 42 | 43 | mtcars_db <- tbl_memdb(mtcars) 44 | mtcars_db \%>\% group_by(cyl) \%>\% summarise(n = n()) \%>\% show_query() 45 | } 46 | -------------------------------------------------------------------------------- /man/named_commas.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{named_commas} 4 | \alias{named_commas} 5 | \title{Provides comma-separated string out of the parameters} 6 | \usage{ 7 | named_commas(x) 8 | } 9 | \description{ 10 | Provides comma-separated string out of the parameters 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/nycflights13.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data-nycflights13.R 3 | \name{nycflights13} 4 | \alias{nycflights13} 5 | \alias{nycflights13_sqlite} 6 | \alias{nycflights13_postgres} 7 | \alias{has_nycflights13} 8 | \alias{copy_nycflights13} 9 | \title{Database versions of the nycflights13 data} 10 | \usage{ 11 | nycflights13_sqlite(path = NULL) 12 | 13 | nycflights13_postgres(dbname = "nycflights13", ...) 14 | 15 | has_nycflights13(type = c("sqlite", "postgres"), ...) 16 | 17 | copy_nycflights13(con, ...) 18 | } 19 | \arguments{ 20 | \item{path}{location of SQLite database file} 21 | 22 | \item{dbname, ...}{Arguments passed on to \code{\link[=src_postgres]{src_postgres()}}} 23 | } 24 | \description{ 25 | These functions cache the data from the \code{nycflights13} database in 26 | a local database, for use in examples and vignettes. Indexes are created 27 | to making joining tables on natural keys efficient. 28 | } 29 | \keyword{internal} 30 | -------------------------------------------------------------------------------- /man/pull.tbl_sql.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-pull.R 3 | \name{pull.tbl_sql} 4 | \alias{pull.tbl_sql} 5 | \title{Extract a single column} 6 | \usage{ 7 | \method{pull}{tbl_sql}(.data, var = -1, name = NULL, ...) 8 | } 9 | \arguments{ 10 | \item{.data}{A lazy data frame backed by a database query.} 11 | 12 | \item{var}{A variable specified as: 13 | \itemize{ 14 | \item a literal variable name 15 | \item a positive integer, giving the position counting from the left 16 | \item a negative integer, giving the position counting from the right. 17 | } 18 | 19 | The default returns the last column (on the assumption that's the 20 | column you've created most recently). 21 | 22 | This argument is taken by expression and supports 23 | \link[rlang:topic-inject]{quasiquotation} (you can unquote column 24 | names and column locations).} 25 | 26 | \item{name}{An optional parameter that specifies the column to be used 27 | as names for a named vector. Specified in a similar manner as \code{var}.} 28 | 29 | \item{...}{<\code{\link[rlang:args_data_masking]{data-masking}}> Variables, or 30 | functions of variables. Use \code{\link[dplyr:desc]{desc()}} to sort a variable in descending 31 | order.} 32 | } 33 | \value{ 34 | A vector of data. 35 | } 36 | \description{ 37 | This is a method for the dplyr \code{\link[=pull]{pull()}} generic. It evaluates the query 38 | retrieving just the specified column. 39 | } 40 | \examples{ 41 | library(dplyr, warn.conflicts = FALSE) 42 | 43 | db <- memdb_frame(x = 1:5, y = 5:1) 44 | db \%>\% 45 | mutate(z = x + y * 2) \%>\% 46 | pull() 47 | } 48 | -------------------------------------------------------------------------------- /man/reexports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reexport.R 3 | \docType{import} 4 | \name{reexports} 5 | \alias{reexports} 6 | \alias{\%>\%} 7 | \title{Objects exported from other packages} 8 | \keyword{internal} 9 | \description{ 10 | These objects are imported from other packages. Follow the links 11 | below to see their documentation. 12 | 13 | \describe{ 14 | \item{magrittr}{\code{\link[magrittr:pipe]{\%>\%}}} 15 | }} 16 | 17 | -------------------------------------------------------------------------------- /man/replace_na.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-expand.R 3 | \name{replace_na.tbl_lazy} 4 | \alias{replace_na.tbl_lazy} 5 | \title{Replace NAs with specified values} 6 | \usage{ 7 | \method{replace_na}{tbl_lazy}(data, replace = list(), ...) 8 | } 9 | \arguments{ 10 | \item{data}{A pair of lazy data frame backed by database queries.} 11 | 12 | \item{replace}{A named list of values, with one value for each column that 13 | has NA values to be replaced.} 14 | 15 | \item{...}{Unused; included for compatibility with generic.} 16 | } 17 | \value{ 18 | Another \code{tbl_lazy}. Use \code{\link[=show_query]{show_query()}} to see the generated 19 | query, and use \code{\link[=collect.tbl_sql]{collect()}} to execute the query 20 | and return data to R. 21 | } 22 | \description{ 23 | This is a method for the \code{\link[tidyr:replace_na]{tidyr::replace_na()}} generic. 24 | } 25 | \examples{ 26 | \dontshow{if (rlang::is_installed("tidyr", version = "1.0.0")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 27 | df <- memdb_frame(x = c(1, 2, NA), y = c("a", NA, "b")) 28 | df \%>\% tidyr::replace_na(list(x = 0, y = "unknown")) 29 | \dontshow{\}) # examplesIf} 30 | } 31 | -------------------------------------------------------------------------------- /man/select.tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-select.R 3 | \name{select.tbl_lazy} 4 | \alias{select.tbl_lazy} 5 | \alias{rename.tbl_lazy} 6 | \alias{rename_with.tbl_lazy} 7 | \alias{relocate.tbl_lazy} 8 | \title{Subset, rename, and reorder columns using their names} 9 | \usage{ 10 | \method{select}{tbl_lazy}(.data, ...) 11 | 12 | \method{rename}{tbl_lazy}(.data, ...) 13 | 14 | \method{rename_with}{tbl_lazy}(.data, .fn, .cols = everything(), ...) 15 | 16 | \method{relocate}{tbl_lazy}(.data, ..., .before = NULL, .after = NULL) 17 | } 18 | \arguments{ 19 | \item{.data}{A lazy data frame backed by a database query.} 20 | 21 | \item{...}{<\code{\link[rlang:args_data_masking]{data-masking}}> Variables, or 22 | functions of variables. Use \code{\link[dplyr:desc]{desc()}} to sort a variable in descending 23 | order.} 24 | 25 | \item{.fn}{A function used to transform the selected \code{.cols}. Should 26 | return a character vector the same length as the input.} 27 | 28 | \item{.cols}{<\code{\link[dplyr:dplyr_tidy_select]{tidy-select}}> Columns to rename; 29 | defaults to all columns.} 30 | 31 | \item{.before, .after}{<\code{\link[dplyr:dplyr_tidy_select]{tidy-select}}> Destination of 32 | columns selected by \code{...}. Supplying neither will move columns to the 33 | left-hand side; specifying both is an error.} 34 | } 35 | \description{ 36 | These are methods for the dplyr \code{\link[=select]{select()}}, \code{\link[=rename]{rename()}}, and \code{\link[=relocate]{relocate()}} 37 | generics. They generate the \code{SELECT} clause of the SQL query. 38 | 39 | These functions do not support predicate functions, i.e. you can 40 | not use \code{where(is.numeric)} to select all numeric variables. 41 | } 42 | \examples{ 43 | library(dplyr, warn.conflicts = FALSE) 44 | 45 | db <- memdb_frame(x = 1, y = 2, z = 3) 46 | db \%>\% select(-y) \%>\% show_query() 47 | db \%>\% relocate(z) \%>\% show_query() 48 | db \%>\% rename(first = x, last = z) \%>\% show_query() 49 | } 50 | -------------------------------------------------------------------------------- /man/simulate_dbi.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/simulate.R 3 | \name{simulate_dbi} 4 | \alias{simulate_dbi} 5 | \title{Simulate database connections} 6 | \usage{ 7 | simulate_dbi(class = character(), ...) 8 | } 9 | \description{ 10 | These functions generate S3 objects that have been designed to simulate 11 | the action of a database connection, without actually having the database 12 | available. Obviously, this simulation can only be incomplete, but most 13 | importantly it allows us to simulate SQL generation for any database without 14 | actually connecting to it. 15 | } 16 | \details{ 17 | Simulated SQL always quotes identifies with \code{`x`}, and strings with 18 | \code{'x'}. 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/sql.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sql.R 3 | \name{sql} 4 | \alias{sql} 5 | \alias{is.sql} 6 | \alias{as.sql} 7 | \title{SQL escaping.} 8 | \usage{ 9 | sql(...) 10 | 11 | is.sql(x) 12 | 13 | as.sql(x, con) 14 | } 15 | \arguments{ 16 | \item{...}{Character vectors that will be combined into a single SQL 17 | expression.} 18 | 19 | \item{x}{Object to coerce} 20 | 21 | \item{con}{Needed when \code{x} is directly supplied from the user so that 22 | schema specifications can be quoted using the correct identifiers.} 23 | } 24 | \description{ 25 | These functions are critical when writing functions that translate R 26 | functions to sql functions. Typically a conversion function should escape 27 | all its inputs and return an sql object. 28 | } 29 | -------------------------------------------------------------------------------- /man/sql_expr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sql-expr.R 3 | \name{sql_expr} 4 | \alias{sql_expr} 5 | \alias{sql_call2} 6 | \title{Generate SQL from R expressions} 7 | \usage{ 8 | sql_expr(x, con = sql_current_con()) 9 | 10 | sql_call2(.fn, ..., con = sql_current_con()) 11 | } 12 | \arguments{ 13 | \item{x}{A quasiquoted expression} 14 | 15 | \item{con}{Connection to use for escaping. Will be set automatically when 16 | called from a function translation.} 17 | 18 | \item{.fn}{Function name (as string, call, or symbol)} 19 | 20 | \item{...}{Arguments to function} 21 | } 22 | \description{ 23 | Low-level building block for generating SQL from R expressions. 24 | Strings are escaped; names become bare SQL identifiers. User infix 25 | functions have \verb{\%} stripped. 26 | } 27 | \details{ 28 | Using \code{sql_expr()} in package will require use of \code{\link[=globalVariables]{globalVariables()}} 29 | to avoid \verb{R CMD check} NOTES. This is a small amount of additional pain, 30 | which I think is worthwhile because it leads to more readable translation 31 | code. 32 | } 33 | \examples{ 34 | con <- simulate_dbi() # not necessary when writing translations 35 | 36 | sql_expr(f(x + 1), con = con) 37 | sql_expr(f("x", "y"), con = con) 38 | sql_expr(f(x, y), con = con) 39 | 40 | x <- ident("x") 41 | sql_expr(f(!!x, y), con = con) 42 | 43 | sql_expr(cast("x" \%as\% DECIMAL), con = con) 44 | sql_expr(round(x) \%::\% numeric, con = con) 45 | 46 | sql_call2("+", quote(x), 1, con = con) 47 | sql_call2("+", "x", 1, con = con) 48 | } 49 | \keyword{internal} 50 | -------------------------------------------------------------------------------- /man/sql_options.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db.R 3 | \name{sql_options} 4 | \alias{sql_options} 5 | \title{Options for generating SQL} 6 | \usage{ 7 | sql_options(cte = FALSE, use_star = TRUE, qualify_all_columns = FALSE) 8 | } 9 | \arguments{ 10 | \item{cte}{If \code{FALSE}, the default, subqueries are used. If \code{TRUE} common 11 | table expressions are used.} 12 | 13 | \item{use_star}{If \code{TRUE}, the default, \code{*} is used to select all columns of 14 | a table. If \code{FALSE} all columns are explicitly selected.} 15 | 16 | \item{qualify_all_columns}{If \code{FALSE}, the default, columns are only 17 | qualified with the table they come from if the same column name appears in 18 | multiple tables.} 19 | } 20 | \value{ 21 | A object. 22 | } 23 | \description{ 24 | Options for generating SQL 25 | } 26 | \examples{ 27 | library(dplyr, warn.conflicts = FALSE) 28 | lf1 <- lazy_frame(key = 1, a = 1, b = 2) 29 | lf2 <- lazy_frame(key = 1, a = 1, c = 3) 30 | 31 | result <- left_join(lf1, lf2, by = "key") \%>\% 32 | filter(c >= 3) 33 | 34 | show_query(result) 35 | sql_options <- sql_options(cte = TRUE, qualify_all_columns = TRUE) 36 | show_query(result, sql_options = sql_options) 37 | } 38 | -------------------------------------------------------------------------------- /man/sql_quote.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/escape.R 3 | \name{sql_quote} 4 | \alias{sql_quote} 5 | \title{Helper function for quoting sql elements.} 6 | \usage{ 7 | sql_quote(x, quote) 8 | } 9 | \arguments{ 10 | \item{x}{Character vector to escape.} 11 | 12 | \item{quote}{Single quoting character.} 13 | } 14 | \description{ 15 | If the quote character is present in the string, it will be doubled. 16 | \code{NA}s will be replaced with NULL. 17 | } 18 | \examples{ 19 | sql_quote("abc", "'") 20 | sql_quote("I've had a good day", "'") 21 | sql_quote(c("abc", NA), "'") 22 | } 23 | \keyword{internal} 24 | -------------------------------------------------------------------------------- /man/src_dbi.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/src_dbi.R 3 | \name{src_dbi} 4 | \alias{src_dbi} 5 | \title{Database src} 6 | \usage{ 7 | src_dbi(con, auto_disconnect = FALSE) 8 | } 9 | \arguments{ 10 | \item{con}{An object that inherits from \link[DBI:DBIConnection-class]{DBI::DBIConnection}, 11 | typically generated by \link[DBI:dbConnect]{DBI::dbConnect}} 12 | 13 | \item{auto_disconnect}{Should the connection be automatically closed when 14 | the src is deleted? Set to \code{TRUE} if you initialize the connection 15 | the call to \code{src_dbi()}. Pass \code{NA} to auto-disconnect but print a message 16 | when this happens.} 17 | } 18 | \value{ 19 | An S3 object with class \code{src_dbi}, \code{src_sql}, \code{src}. 20 | } 21 | \description{ 22 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} 23 | 24 | Since can generate a \code{tbl()} directly from a DBI connection we no longer 25 | recommend using \code{src_dbi()}. 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /man/src_sql.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/src-sql.R 3 | \name{src_sql} 4 | \alias{src_sql} 5 | \title{Create a "sql src" object} 6 | \usage{ 7 | src_sql(subclass, con, ...) 8 | } 9 | \arguments{ 10 | \item{subclass}{name of subclass. "src_sql" is an abstract base class, so you 11 | must supply this value. \code{src_} is automatically prepended to the 12 | class name} 13 | 14 | \item{con}{the connection object} 15 | 16 | \item{...}{fields used by object} 17 | } 18 | \description{ 19 | Deprecated: please use directly use a \code{DBIConnection} object instead. 20 | } 21 | \keyword{internal} 22 | -------------------------------------------------------------------------------- /man/tbl_lazy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tbl-lazy.R 3 | \name{tbl_lazy} 4 | \alias{tbl_lazy} 5 | \alias{lazy_frame} 6 | \title{Create a local lazy tibble} 7 | \usage{ 8 | tbl_lazy(df, con = NULL, ..., name = "df") 9 | 10 | lazy_frame(..., con = NULL, .name = "df") 11 | } 12 | \description{ 13 | These functions are useful for testing SQL generation without having to 14 | have an active database connection. See \code{\link[=simulate_dbi]{simulate_dbi()}} for a list 15 | available database simulations. 16 | } 17 | \examples{ 18 | library(dplyr) 19 | df <- data.frame(x = 1, y = 2) 20 | 21 | df_sqlite <- tbl_lazy(df, con = simulate_sqlite()) 22 | df_sqlite \%>\% summarise(x = sd(x, na.rm = TRUE)) \%>\% show_query() 23 | } 24 | \keyword{internal} 25 | -------------------------------------------------------------------------------- /man/tbl_sql.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tbl-sql.R 3 | \name{tbl_sql} 4 | \alias{tbl_sql} 5 | \title{Create an SQL tbl (abstract)} 6 | \usage{ 7 | tbl_sql(subclass, src, from, ..., vars = NULL, check_from = deprecated()) 8 | } 9 | \arguments{ 10 | \item{subclass}{name of subclass} 11 | 12 | \item{...}{needed for agreement with generic. Not otherwise used.} 13 | 14 | \item{vars}{Provide column names as a character vector 15 | to avoid retrieving them from the database. 16 | Mainly useful for better performance when creating 17 | multiple \code{tbl} objects.} 18 | 19 | \item{check_from}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}}} 20 | } 21 | \description{ 22 | Generally, you should no longer need to provide a custom \code{tbl()} 23 | method. 24 | The default \code{tbl.DBIConnect} method should work in most cases. 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/testing.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/test-frame.R 3 | \name{testing} 4 | \alias{testing} 5 | \alias{test_register_src} 6 | \alias{test_register_con} 7 | \alias{src_test} 8 | \alias{test_load} 9 | \alias{test_frame} 10 | \title{Infrastructure for testing dplyr} 11 | \usage{ 12 | test_register_src(name, src) 13 | 14 | test_register_con(name, ...) 15 | 16 | src_test(name) 17 | 18 | test_load( 19 | df, 20 | name = unique_table_name(), 21 | srcs = test_srcs$get(), 22 | ignore = character() 23 | ) 24 | 25 | test_frame(..., srcs = test_srcs$get(), ignore = character()) 26 | } 27 | \description{ 28 | Register testing sources, then use \code{test_load()} to load an existing 29 | data frame into each source. To create a new table in each source, 30 | use \code{test_frame()}. 31 | } 32 | \examples{ 33 | \dontrun{ 34 | test_register_src("sqlite", { 35 | DBI::dbConnect(RSQLite::SQLite(), ":memory:", create = TRUE) 36 | }) 37 | 38 | test_frame(x = 1:3, y = 3:1) 39 | test_load(mtcars) 40 | } 41 | } 42 | \keyword{internal} 43 | -------------------------------------------------------------------------------- /man/win_over.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/translate-sql-window.R, R/backend-teradata.R 3 | \name{win_over} 4 | \alias{win_over} 5 | \alias{win_rank} 6 | \alias{win_aggregate} 7 | \alias{win_aggregate_2} 8 | \alias{win_recycled} 9 | \alias{win_cumulative} 10 | \alias{win_absent} 11 | \alias{win_current_group} 12 | \alias{win_current_order} 13 | \alias{win_current_frame} 14 | \alias{win_rank_tdata} 15 | \title{Generate SQL expression for window functions} 16 | \usage{ 17 | win_over( 18 | expr, 19 | partition = NULL, 20 | order = NULL, 21 | frame = NULL, 22 | con = sql_current_con() 23 | ) 24 | 25 | win_rank(f, empty_order = FALSE) 26 | 27 | win_aggregate(f) 28 | 29 | win_aggregate_2(f) 30 | 31 | win_cumulative(f) 32 | 33 | win_absent(f) 34 | 35 | win_current_group() 36 | 37 | win_current_order() 38 | 39 | win_current_frame() 40 | 41 | win_rank_tdata(f) 42 | } 43 | \arguments{ 44 | \item{expr}{The window expression} 45 | 46 | \item{partition}{Variables to partition over} 47 | 48 | \item{order}{Variables to order by} 49 | 50 | \item{frame}{A numeric vector of length two defining the frame.} 51 | 52 | \item{f}{The name of an sql function as a string} 53 | 54 | \item{empty_order}{A logical value indicating whether to order by NULL if \code{order} is not specified} 55 | } 56 | \description{ 57 | \code{win_over()} makes it easy to generate the window function specification. 58 | \code{win_absent()}, \code{win_rank()}, \code{win_aggregate()}, and \code{win_cumulative()} 59 | provide helpers for constructing common types of window functions. 60 | \code{win_current_group()} and \code{win_current_order()} allow you to access 61 | the grouping and order context set up by \code{\link[=group_by]{group_by()}} and \code{\link[=arrange]{arrange()}}. 62 | } 63 | \examples{ 64 | con <- simulate_dbi() 65 | 66 | win_over(sql("avg(x)"), con = con) 67 | win_over(sql("avg(x)"), "y", con = con) 68 | win_over(sql("avg(x)"), order = "y", con = con) 69 | win_over(sql("avg(x)"), order = c("x", "y"), con = con) 70 | win_over(sql("avg(x)"), frame = c(-Inf, 0), order = "y", con = con) 71 | } 72 | \keyword{internal} 73 | -------------------------------------------------------------------------------- /man/window_order.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/verb-window.R 3 | \name{window_order} 4 | \alias{window_order} 5 | \alias{window_frame} 6 | \title{Override window order and frame} 7 | \usage{ 8 | window_order(.data, ...) 9 | 10 | window_frame(.data, from = -Inf, to = Inf) 11 | } 12 | \arguments{ 13 | \item{.data}{A lazy data frame backed by a database query.} 14 | 15 | \item{...}{Variables to order by} 16 | 17 | \item{from, to}{Bounds of the frame.} 18 | } 19 | \description{ 20 | These allow you to override the \verb{PARTITION BY} and \verb{ORDER BY} clauses 21 | of window functions generated by grouped mutates. 22 | } 23 | \examples{ 24 | library(dplyr, warn.conflicts = FALSE) 25 | 26 | db <- memdb_frame(g = rep(1:2, each = 5), y = runif(10), z = 1:10) 27 | db \%>\% 28 | window_order(y) \%>\% 29 | mutate(z = cumsum(y)) \%>\% 30 | show_query() 31 | 32 | db \%>\% 33 | group_by(g) \%>\% 34 | window_frame(-3, 0) \%>\% 35 | window_order(z) \%>\% 36 | mutate(z = sum(y)) \%>\% 37 | show_query() 38 | } 39 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | checks 2 | library 3 | checks.noindex 4 | library.noindex 5 | data.sqlite 6 | *.html 7 | cloud.noindex 8 | -------------------------------------------------------------------------------- /revdep/README.md: -------------------------------------------------------------------------------- 1 | # Revdeps 2 | 3 | ## Failed to check (11) 4 | 5 | |package |version |error |warning |note | 6 | |:------------------|:-------|:-----|:-------|:----| 7 | |BiocFileCache |? | | | | 8 | |BiocOncoTK |? | | | | 9 | |CompoundDb |? | | | | 10 | |CuratedAtlasQueryR |? | | | | 11 | |GEOmetadb |? | | | | 12 | |grasp2db |? | | | | 13 | |msPurity |? | | | | 14 | |NoRCE |? | | | | 15 | |Organism.dplyr |? | | | | 16 | |SQLDataFrame |? | | | | 17 | |synaptome.db |? | | | | 18 | 19 | ## New problems (8) 20 | 21 | |package |version |error |warning |note | 22 | |:-------------------|:-------|:--------|:-------|:----| 23 | |[Andromeda](problems.md#andromeda)|0.6.5 |__+3__ |-1 | | 24 | |[CDMConnector](problems.md#cdmconnector)|1.3.0 |__+2__ | |1 | 25 | |[CohortSurvival](problems.md#cohortsurvival)|0.3.0 |__+2__ | | | 26 | |[diseasystore](problems.md#diseasystore)|0.1.1 |__+1__ | | | 27 | |[DrugUtilisation](problems.md#drugutilisation)|0.5.2 |__+2__ | | | 28 | |[IncidencePrevalence](problems.md#incidenceprevalence)|0.7.1 |__+2__ | | | 29 | |[PatientProfiles](problems.md#patientprofiles)|0.6.2 |1 __+1__ | | | 30 | |[SCDB](problems.md#scdb)|0.3 |__+3__ | | | 31 | 32 | -------------------------------------------------------------------------------- /revdep/check.R: -------------------------------------------------------------------------------- 1 | library("devtools") 2 | 3 | install.packages("RPostgreSQL", lib = getOption("devtools.revdep.libpath")) 4 | install.packages("bit64", lib = getOption("devtools.revdep.libpath")) 5 | install.packages("rJava", lib = getOption("devtools.revdep.libpath")) 6 | 7 | revdep_check() 8 | revdep_check_save_summary() 9 | revdep_check_print_problems() 10 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 112 reverse dependencies (101 from CRAN + 11 from Bioconductor), comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 8 new problems 6 | * We failed to check 0 packages 7 | 8 | Issues with CRAN packages are summarised below. 9 | 10 | ### New problems 11 | (This reports the first line of each new failure) 12 | 13 | * Andromeda 14 | checking examples ... ERROR 15 | checking tests ... ERROR 16 | checking re-building of vignette outputs ... ERROR 17 | 18 | * CDMConnector 19 | checking tests ... ERROR 20 | checking re-building of vignette outputs ... ERROR 21 | 22 | * CohortSurvival 23 | checking tests ... ERROR 24 | checking re-building of vignette outputs ... ERROR 25 | 26 | * diseasystore 27 | checking tests ... ERROR 28 | 29 | * DrugUtilisation 30 | checking tests ... ERROR 31 | checking re-building of vignette outputs ... ERROR 32 | 33 | * IncidencePrevalence 34 | checking tests ... ERROR 35 | checking re-building of vignette outputs ... ERROR 36 | 37 | * PatientProfiles 38 | checking re-building of vignette outputs ... ERROR 39 | 40 | * SCDB 41 | checking examples ... ERROR 42 | checking tests ... ERROR 43 | checking re-building of vignette outputs ... ERROR 44 | 45 | -------------------------------------------------------------------------------- /revdep/email.yml: -------------------------------------------------------------------------------- 1 | release_date: April 22 2 | rel_release_date: 1 week 3 | my_news_url: https://github.com/tidyverse/dbplyr/blob/master/NEWS.md#dbplyr-development-version 4 | release_version: 1.4.0 5 | release_details: > 6 | This is a major release with a bunch of improvements to SQL generation, 7 | so I'd really appreciate your help checking that I haven't broken 8 | any existing translations. 9 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(dbplyr) 3 | 4 | test_check("dbplyr") 5 | -------------------------------------------------------------------------------- /tests/testthat/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite3 -------------------------------------------------------------------------------- /tests/testthat/_snaps/backend-access.md: -------------------------------------------------------------------------------- 1 | # custom scalar translated correctly 2 | 3 | Code 4 | test_translate_sql(paste(x, collapse = "-")) 5 | Condition 6 | Error in `check_collapse()`: 7 | ! `collapse` not supported in DB translation of `paste()`. 8 | i Please use `str_flatten()` instead. 9 | 10 | # queries translate correctly 11 | 12 | Code 13 | mf %>% head() 14 | Output 15 | 16 | SELECT TOP 6 `df`.* 17 | FROM `df` 18 | 19 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/backend-hana.md: -------------------------------------------------------------------------------- 1 | # custom string translations 2 | 3 | Code 4 | test_translate_sql(paste0("a", "b")) 5 | Output 6 | 'a' || 'b' 7 | 8 | --- 9 | 10 | Code 11 | test_translate_sql(paste("a", "b")) 12 | Output 13 | 'a' || ' ' || 'b' 14 | 15 | --- 16 | 17 | Code 18 | test_translate_sql(substr(x, 2, 4)) 19 | Output 20 | SUBSTRING(`x`, 2, 3) 21 | 22 | --- 23 | 24 | Code 25 | test_translate_sql(substring(x, 2, 4)) 26 | Output 27 | SUBSTRING(`x`, 2, 3) 28 | 29 | --- 30 | 31 | Code 32 | test_translate_sql(str_sub(x, 2, -2)) 33 | Output 34 | SUBSTRING(`x`, 2, LENGTH(`x`) - 2) 35 | 36 | # copy_inline uses UNION ALL 37 | 38 | Code 39 | copy_inline(con, y %>% slice(0)) %>% remote_query() 40 | Output 41 | SELECT CAST(NULL AS INTEGER) AS `id`, CAST(NULL AS VARCHAR) AS `arr` 42 | FROM `DUMMY` 43 | WHERE (0 = 1) 44 | Code 45 | copy_inline(con, y) %>% remote_query() 46 | Output 47 | SELECT CAST(`id` AS INTEGER) AS `id`, CAST(`arr` AS VARCHAR) AS `arr` 48 | FROM ( 49 | SELECT NULL AS `id`, NULL AS `arr` 50 | FROM `DUMMY` 51 | WHERE (0 = 1) 52 | 53 | UNION ALL 54 | 55 | SELECT 1, '{1,2,3}' FROM DUMMY 56 | ) AS `values_table` 57 | Code 58 | copy_inline(con, y %>% slice(0), types = types) %>% remote_query() 59 | Output 60 | SELECT CAST(NULL AS bigint) AS `id`, CAST(NULL AS integer[]) AS `arr` 61 | FROM `DUMMY` 62 | WHERE (0 = 1) 63 | Code 64 | copy_inline(con, y, types = types) %>% remote_query() 65 | Output 66 | SELECT CAST(`id` AS bigint) AS `id`, CAST(`arr` AS integer[]) AS `arr` 67 | FROM ( 68 | SELECT NULL AS `id`, NULL AS `arr` 69 | FROM `DUMMY` 70 | WHERE (0 = 1) 71 | 72 | UNION ALL 73 | 74 | SELECT 1, '{1,2,3}' FROM DUMMY 75 | ) AS `values_table` 76 | 77 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/backend-hive.md: -------------------------------------------------------------------------------- 1 | # generates custom sql 2 | 3 | Code 4 | sql_table_analyze(con, in_schema("schema", "tbl")) 5 | Output 6 | ANALYZE TABLE `schema`.`tbl` COMPUTE STATISTICS 7 | 8 | --- 9 | 10 | Code 11 | union_all(lf, lf) 12 | Output 13 | 14 | SELECT * 15 | FROM `df` 16 | 17 | UNION ALL 18 | 19 | SELECT * 20 | FROM `df` 21 | 22 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/backend-impala.md: -------------------------------------------------------------------------------- 1 | # generates custom sql 2 | 3 | Code 4 | sql_table_analyze(con, in_schema("schema", "tbl")) 5 | Output 6 | COMPUTE STATS `schema`.`tbl` 7 | 8 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/backend-snowflake.md: -------------------------------------------------------------------------------- 1 | # pasting translated correctly 2 | 3 | Code 4 | test_translate_sql(paste0(x, collapse = "")) 5 | Condition 6 | Error in `check_collapse()`: 7 | ! `collapse` not supported in DB translation of `paste()`. 8 | i Please use `str_flatten()` instead. 9 | 10 | # pmin() and pmax() respect na.rm 11 | 12 | Code 13 | test_translate_sql(pmin(x, y, z, na.rm = TRUE)) 14 | Output 15 | COALESCE(IFF(COALESCE(IFF(`x` <= `y`, `x`, `y`), `x`, `y`) <= `z`, COALESCE(IFF(`x` <= `y`, `x`, `y`), `x`, `y`), `z`), COALESCE(IFF(`x` <= `y`, `x`, `y`), `x`, `y`), `z`) 16 | 17 | --- 18 | 19 | Code 20 | test_translate_sql(pmax(x, y, z, na.rm = TRUE)) 21 | Output 22 | COALESCE(IFF(COALESCE(IFF(`x` >= `y`, `x`, `y`), `x`, `y`) >= `z`, COALESCE(IFF(`x` >= `y`, `x`, `y`), `x`, `y`), `z`), COALESCE(IFF(`x` >= `y`, `x`, `y`), `x`, `y`), `z`) 23 | 24 | # row_number() with and without group_by() and arrange(): unordered defaults to Ordering by NULL (per empty_order) 25 | 26 | Code 27 | mf %>% mutate(rown = row_number()) 28 | Output 29 | 30 | SELECT `df`.*, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS `rown` 31 | FROM `df` 32 | 33 | --- 34 | 35 | Code 36 | mf %>% group_by(y) %>% mutate(rown = row_number()) 37 | Output 38 | 39 | SELECT 40 | `df`.*, 41 | ROW_NUMBER() OVER (PARTITION BY `y` ORDER BY (SELECT NULL)) AS `rown` 42 | FROM `df` 43 | 44 | --- 45 | 46 | Code 47 | mf %>% arrange(y) %>% mutate(rown = row_number()) 48 | Output 49 | 50 | SELECT `df`.*, ROW_NUMBER() OVER (ORDER BY `y`) AS `rown` 51 | FROM `df` 52 | ORDER BY `y` 53 | 54 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/backend-spark-sql.md: -------------------------------------------------------------------------------- 1 | # custom clock functions translated correctly 2 | 3 | Code 4 | test_translate_sql(date_count_between(date_column_1, date_column_2, "year")) 5 | Condition 6 | Error in `date_count_between()`: 7 | ! `precision = "year"` isn't supported on database backends. 8 | i It must be "day" instead. 9 | 10 | --- 11 | 12 | Code 13 | test_translate_sql(date_count_between(date_column_1, date_column_2, "day", n = 5)) 14 | Condition 15 | Error in `date_count_between()`: 16 | ! `n = 5` isn't supported on database backends. 17 | i It must be 1 instead. 18 | 19 | # difftime is translated correctly 20 | 21 | Code 22 | test_translate_sql(difftime(start_date, end_date, units = "auto")) 23 | Condition 24 | Error in `difftime()`: 25 | ! `units = "auto"` isn't supported on database backends. 26 | i It must be "days" instead. 27 | 28 | --- 29 | 30 | Code 31 | test_translate_sql(difftime(start_date, end_date, tz = "UTC", units = "days")) 32 | Condition 33 | Error in `difftime()`: 34 | ! Argument `tz` isn't supported on database backends. 35 | 36 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/backend-sqlite.md: -------------------------------------------------------------------------------- 1 | # custom SQL translation 2 | 3 | Code 4 | left_join(lf, lf, by = "x", na_matches = "na") 5 | Output 6 | 7 | SELECT `df_LHS`.`x` AS `x` 8 | FROM `df` AS `df_LHS` 9 | LEFT JOIN `df` AS `df_RHS` 10 | ON (`df_LHS`.`x` IS `df_RHS`.`x`) 11 | 12 | --- 13 | 14 | Code 15 | test_translate_sql(runif(n())) 16 | Output 17 | (0.5 + RANDOM() / 18446744073709551616.0) 18 | 19 | # case_when translates correctly to ELSE when TRUE ~ is used 20 | 21 | Code 22 | test_translate_sql(case_when(x == 1L ~ "yes", x == 0L ~ "no", TRUE ~ 23 | "undefined"), con = simulate_sqlite()) 24 | Output 25 | CASE WHEN (`x` = 1) THEN 'yes' WHEN (`x` = 0) THEN 'no' ELSE 'undefined' END 26 | 27 | # can explain a query 28 | 29 | Code 30 | db %>% filter(x > 2) %>% explain() 31 | Output 32 | 33 | SELECT `test`.* 34 | FROM `test` 35 | WHERE (`x` > 2.0) 36 | 37 | 38 | id parent notused detail 39 | 1 2 0 35 SEARCH test USING COVERING INDEX test_x (x>?) 40 | 41 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/backend-teradata.md: -------------------------------------------------------------------------------- 1 | # generates custom sql 2 | 3 | Code 4 | sql_table_analyze(con, in_schema("schema", "tbl")) 5 | Output 6 | COLLECT STATISTICS `schema`.`tbl` 7 | 8 | # head translated to TOP 9 | 10 | Code 11 | mf %>% head() %>% sql_render() 12 | Output 13 | SELECT TOP 6 `df`.* 14 | FROM `df` 15 | 16 | # lead, lag work 17 | 18 | Code 19 | mf %>% group_by(y) %>% mutate(val2 = lead(x, order_by = x)) %>% sql_render() 20 | Output 21 | SELECT `df`.*, LEAD(`x`, 1, NULL) OVER (PARTITION BY `y` ORDER BY `x`) AS `val2` 22 | FROM `df` 23 | 24 | --- 25 | 26 | Code 27 | mf %>% group_by(y) %>% mutate(val2 = lag(x, order_by = x)) %>% sql_render() 28 | Output 29 | SELECT `df`.*, LAG(`x`, 1, NULL) OVER (PARTITION BY `y` ORDER BY `x`) AS `val2` 30 | FROM `df` 31 | 32 | # weighted.mean 33 | 34 | Code 35 | mf %>% summarise(wt_mean = weighted.mean(x, y)) 36 | Output 37 | 38 | SELECT SUM((`x` * `y`)) / SUM(`y`) OVER () AS `wt_mean` 39 | FROM `df` 40 | 41 | # row_number() with and without group_by() and arrange(): unordered defaults to Ordering by NULL (per empty_order) 42 | 43 | Code 44 | mf %>% mutate(rown = row_number()) 45 | Output 46 | 47 | SELECT `df`.*, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS `rown` 48 | FROM `df` 49 | 50 | --- 51 | 52 | Code 53 | mf %>% group_by(y) %>% mutate(rown = row_number()) 54 | Output 55 | 56 | SELECT 57 | `df`.*, 58 | ROW_NUMBER() OVER (PARTITION BY `y` ORDER BY (SELECT NULL)) AS `rown` 59 | FROM `df` 60 | 61 | --- 62 | 63 | Code 64 | mf %>% arrange(y) %>% mutate(rown = row_number()) 65 | Output 66 | 67 | SELECT `df`.*, ROW_NUMBER() OVER (ORDER BY `y`) AS `rown` 68 | FROM `df` 69 | ORDER BY `y` 70 | 71 | # head after distinct() produces subquery 72 | 73 | Code 74 | lf %>% distinct() %>% head() 75 | Output 76 | 77 | SELECT TOP 6 `q01`.* 78 | FROM ( 79 | SELECT DISTINCT `df`.* 80 | FROM `df` 81 | ) AS `q01` 82 | 83 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/build-sql.md: -------------------------------------------------------------------------------- 1 | # build_sql() requires connection 2 | 3 | Code 4 | build_sql("SELECT * FROM ", x) 5 | Condition 6 | Error in `build_sql()`: 7 | ! `con` must not be NULL. 8 | 9 | # glue_sql() checks size 10 | 11 | Code 12 | glue_sql2("{.col x}", .con = con) 13 | Condition 14 | Error in `.transformer()`: 15 | ! `value` must have size 1, not 2. 16 | Code 17 | glue_sql2("{.col character()}", .con = con) 18 | Condition 19 | Error in `.transformer()`: 20 | ! `value` must have size 1, not 0. 21 | 22 | # glue_sql() can collapse 23 | 24 | Code 25 | glue_sql2("{.tbl x*}", .con = con) 26 | Condition 27 | Error in `glue_check_collapse()`: 28 | ! Collapsing is only allowed for "col" and "val", not for "tbl". 29 | Code 30 | glue_sql2("{.name x*}", .con = con) 31 | Condition 32 | Error in `glue_check_collapse()`: 33 | ! Collapsing is only allowed for "col" and "val", not for "name". 34 | Code 35 | glue_sql2("{.from x*}", .con = con) 36 | Condition 37 | Error in `glue_check_collapse()`: 38 | ! Collapsing is only allowed for "col" and "val", not for "from". 39 | 40 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/db-io.md: -------------------------------------------------------------------------------- 1 | # db_copy_to() wraps DBI errors 2 | 3 | Code 4 | (expect_error(db_copy_to(con = con, table = "tmp2", values = data.frame(x = c(1, 5 | 1)), unique_indexes = list("x")))) 6 | Output 7 | 8 | Error in `db_copy_to()`: 9 | ! Can't copy data to table `tmp2`. 10 | Caused by error in `db_create_index.DBIConnection()`: 11 | ! Can't create index on table `tmp2`. 12 | i Using SQL: CREATE UNIQUE INDEX `tmp2_x` ON `tmp2` (`x`) 13 | Caused by error: 14 | ! dummy DBI error 15 | 16 | # db_copy_to() can overwrite a table 17 | 18 | Code 19 | (expect_error(db_copy_to(con = con, table = "tmp", values = data.frame(x = c(1, 20 | 1))))) 21 | Output 22 | 23 | Error in `db_copy_to()`: 24 | ! Can't copy data to table `tmp`. 25 | Caused by error in `dplyr::db_write_table()`: 26 | ! Can't write table table `tmp`. 27 | Caused by error: 28 | ! dummy DBI error 29 | 30 | # db_save_query() can overwrite a table 31 | 32 | Code 33 | (expect_error(db_save_query(con = con, sql = "SELECT 2 FROM tmp", name = "tmp")) 34 | ) 35 | Output 36 | 37 | Error in `db_save_query()`: 38 | ! Can't save query to table `tmp`. 39 | i Using SQL: CREATE TEMPORARY TABLE `tmp` AS `SELECT 2 FROM tmp` 40 | Caused by error: 41 | ! dummy DBI error 42 | 43 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/db-sql.md: -------------------------------------------------------------------------------- 1 | # 2nd edition uses sql methods 2 | 3 | Code 4 | expect_error(dbplyr_analyze(con), "db_method") 5 | Condition 6 | Warning: 7 | uses an old dbplyr interface 8 | i Please install a newer version of the package or contact the maintainer 9 | This warning is displayed once every 8 hours. 10 | 11 | # handles DBI error 12 | 13 | Code 14 | (expect_error(db_analyze(con, "tbl"))) 15 | Output 16 | 17 | Error in `db_analyze()`: 18 | ! Can't analyze table tbl. 19 | i Using SQL: ANALYZE `tbl` 20 | Caused by error: 21 | ! dummy DBI error 22 | Code 23 | (expect_error(db_create_index(con, "tbl", "col"))) 24 | Output 25 | 26 | Error in `db_create_index()`: 27 | ! Can't create index on table tbl. 28 | i Using SQL: CREATE INDEX `tbl_col` ON `tbl` (`col`) 29 | Caused by error: 30 | ! dummy DBI error 31 | Code 32 | (expect_error(db_explain(con, "invalid sql"))) 33 | Output 34 | 35 | Error in `db_explain()`: 36 | ! Can't explain query. 37 | i Using SQL: EXPLAIN QUERY PLAN invalid sql 38 | Caused by error: 39 | ! dummy DBI error 40 | Code 41 | (expect_error(db_query_fields(con, "does not exist"))) 42 | Output 43 | 44 | Error in `db_query_fields()`: 45 | ! Can't query fields. 46 | i Using SQL: SELECT * FROM `does not exist` AS `q01` WHERE (0 = 1) 47 | Caused by error: 48 | ! dummy DBI error 49 | Code 50 | (expect_error(db_save_query(con, "invalid sql", "tbl"))) 51 | Output 52 | 53 | Error in `db_save_query()`: 54 | ! Can't save query to table `tbl`. 55 | i Using SQL: CREATE TEMPORARY TABLE `tbl` AS `invalid sql` 56 | Caused by error: 57 | ! dummy DBI error 58 | 59 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/escape.md: -------------------------------------------------------------------------------- 1 | # con must not be NULL 2 | 3 | Code 4 | escape("a") 5 | Condition 6 | Error in `escape()`: 7 | ! `con` must not be NULL. 8 | 9 | --- 10 | 11 | Code 12 | sql_vector("a") 13 | Condition 14 | Error in `sql_vector()`: 15 | ! `con` must not be NULL. 16 | 17 | # other objects get informative error 18 | 19 | Code 20 | lf %>% filter(x == input) 21 | Condition 22 | Error: 23 | ! Cannot translate shiny inputs to SQL. 24 | i Do you want to force evaluation in R with (e.g.) `!!input$x` or `local(input$x)`? 25 | Code 26 | lf %>% filter(x == x()) 27 | Condition 28 | Error: 29 | ! Cannot translate a shiny reactive to SQL. 30 | i Do you want to force evaluation in R with (e.g.) `!!foo()` or `local(foo())`? 31 | Code 32 | lf %>% filter(x == df) 33 | Condition 34 | Error: 35 | ! Cannot translate a data.frame to SQL. 36 | i Do you want to force evaluation in R with (e.g.) `!!df$x` or `local(df$x)`? 37 | Code 38 | lf %>% filter(x == mean) 39 | Condition 40 | Error: 41 | ! Cannot translate a function to SQL. 42 | i Do you want to force evaluation in R with (e.g.) `!!x` or `local(x)`? 43 | 44 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/ident.md: -------------------------------------------------------------------------------- 1 | # can format ident 2 | 3 | Code 4 | ident() 5 | Output 6 | [empty] 7 | 8 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/lazy-join-query.md: -------------------------------------------------------------------------------- 1 | # lazy_semi_join_query() checks arguments 2 | 3 | Code 4 | (my_lazy_semi_join_query(x = lazy_frame(x = 1))) 5 | Condition 6 | Error in `my_lazy_semi_join_query()`: 7 | ! `x` must be a lazy query, not a object. 8 | Code 9 | (my_lazy_semi_join_query(y = lazy_frame(x = 1))) 10 | Condition 11 | Error in `my_lazy_semi_join_query()`: 12 | ! `y` must be a lazy query, not a object. 13 | 14 | --- 15 | 16 | Code 17 | (my_lazy_semi_join_query(by = lmod(by0, x = 1))) 18 | Condition 19 | Error in `my_lazy_semi_join_query()`: 20 | ! `by$x` must be a character vector, not the number 1. 21 | 22 | --- 23 | 24 | Code 25 | (my_lazy_semi_join_query(anti = NA)) 26 | Condition 27 | Error in `my_lazy_semi_join_query()`: 28 | ! `anti` must be `TRUE` or `FALSE`, not `NA`. 29 | 30 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/lazy-select-query.md: -------------------------------------------------------------------------------- 1 | # can print lazy_select_query 2 | 3 | Code 4 | lazy_select_query(x = lf$lazy_query, select = quos(x_mean = mean(x), y2 = y), 5 | where = quos(y > 1, x == y - 2), group_by = quos("x")) 6 | Output 7 | 8 | From: 9 | `df` 10 | Select: x_mean = mean(x), y2 = y 11 | Where: y > 1, x == y - 2 12 | Group by: "x" 13 | 14 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/pillar.md: -------------------------------------------------------------------------------- 1 | # custom header 2 | 3 | Code 4 | # Number of rows is shown 5 | x <- memdb_frame(a = 1:3) %>% filter(a > 0) 6 | setup <- pillar::tbl_format_setup(x) 7 | tbl_format_header(x, setup)[[1]] 8 | Output 9 | [1] "# Source: SQL [3 x 1]" 10 | Code 11 | # Number of rows still can't be shown if above 20 12 | x <- memdb_frame(a = 1:21) %>% filter(a > 0) 13 | setup <- pillar::tbl_format_setup(x) 14 | tbl_format_header(x, setup)[[1]] 15 | Output 16 | [1] "# Source: SQL [?? x 1]" 17 | 18 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/query-select.md: -------------------------------------------------------------------------------- 1 | # select_query() print method output is as expected 2 | 3 | Code 4 | mf 5 | Output 6 | 7 | From: 8 | `df` 9 | Select: `df`.* 10 | Where: `x` > 1 11 | Order by: `x` 12 | Limit: 10 13 | 14 | # queries generated by select() don't alias unnecessarily 15 | 16 | Code 17 | lf_render 18 | Output 19 | SELECT `x` 20 | FROM `df` 21 | 22 | --- 23 | 24 | Code 25 | lazy_frame(x = 1, y = 1) %>% select() 26 | Condition 27 | Error in `sql_clause_select()`: 28 | ! Query contains no columns 29 | 30 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/query-semi-join.md: -------------------------------------------------------------------------------- 1 | # print method doesn't change unexpectedly 2 | 3 | Code 4 | sql_build(semi_join(lf1, lf2 %>% filter(z == 2))) 5 | Message 6 | Joining with `by = join_by(x)` 7 | Output 8 | 9 | By: 10 | x-x 11 | Where: 12 | "`df_RHS`.`z` = 2.0" 13 | X: 14 | `df` 15 | Y: 16 | `df` 17 | 18 | # generated sql doesn't change unexpectedly 19 | 20 | Code 21 | semi_join(lf, lf) 22 | Message 23 | Joining with `by = join_by(x, y)` 24 | Output 25 | 26 | SELECT `df_LHS`.* 27 | FROM `df` AS `df_LHS` 28 | WHERE EXISTS ( 29 | SELECT 1 FROM `df` AS `df_RHS` 30 | WHERE (`df_LHS`.`x` = `df_RHS`.`x`) AND (`df_LHS`.`y` = `df_RHS`.`y`) 31 | ) 32 | 33 | --- 34 | 35 | Code 36 | anti_join(lf, lf) 37 | Message 38 | Joining with `by = join_by(x, y)` 39 | Output 40 | 41 | SELECT `df_LHS`.* 42 | FROM `df` AS `df_LHS` 43 | WHERE NOT EXISTS ( 44 | SELECT 1 FROM `df` AS `df_RHS` 45 | WHERE (`df_LHS`.`x` = `df_RHS`.`x`) AND (`df_LHS`.`y` = `df_RHS`.`y`) 46 | ) 47 | 48 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/query-set-op.md: -------------------------------------------------------------------------------- 1 | # print method doesn't change unexpectedly 2 | 3 | Code 4 | sql_build(union(lf1, lf2) %>% union_all(lf3)) 5 | Output 6 | 7 | From: 8 | `lf1` 9 | Select: `lf1`.*, NULL 10 | 11 | UNION 12 | 13 | 14 | From: 15 | `lf2` 16 | Select: `x`, NULL, `z` 17 | 18 | UNION ALL 19 | 20 | 21 | From: 22 | `lf3` 23 | Select: `x`, NULL, `z` 24 | 25 | # generated sql doesn't change unexpectedly 26 | 27 | Code 28 | union(lf, lf) 29 | Output 30 | 31 | SELECT * 32 | FROM `df` 33 | 34 | UNION 35 | 36 | SELECT * 37 | FROM `df` 38 | 39 | --- 40 | 41 | Code 42 | setdiff(lf, lf) 43 | Output 44 | 45 | ( 46 | SELECT * 47 | FROM `df` 48 | ) 49 | EXCEPT 50 | ( 51 | SELECT * 52 | FROM `df` 53 | ) 54 | 55 | --- 56 | 57 | Code 58 | intersect(lf, lf) 59 | Output 60 | 61 | ( 62 | SELECT * 63 | FROM `df` 64 | ) 65 | INTERSECT 66 | ( 67 | SELECT * 68 | FROM `df` 69 | ) 70 | 71 | --- 72 | 73 | Code 74 | union(lf, lf, all = TRUE) 75 | Output 76 | 77 | SELECT * 78 | FROM `df` 79 | 80 | UNION ALL 81 | 82 | SELECT * 83 | FROM `df` 84 | 85 | --- 86 | 87 | Code 88 | setdiff(lf, lf, all = TRUE) 89 | Output 90 | 91 | ( 92 | SELECT * 93 | FROM `df` 94 | ) 95 | EXCEPT ALL 96 | ( 97 | SELECT * 98 | FROM `df` 99 | ) 100 | 101 | --- 102 | 103 | Code 104 | intersect(lf, lf, all = TRUE) 105 | Output 106 | 107 | ( 108 | SELECT * 109 | FROM `df` 110 | ) 111 | INTERSECT ALL 112 | ( 113 | SELECT * 114 | FROM `df` 115 | ) 116 | 117 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/schema.md: -------------------------------------------------------------------------------- 1 | # can construct and print 2 | 3 | Code 4 | in_schema("schema", "table") 5 | Output 6 | `schema`.`table` 7 | 8 | --- 9 | 10 | Code 11 | in_catalog("catalog", "schema", "table") 12 | Output 13 | `catalog`.`schema`.`table` 14 | 15 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/sql-build.md: -------------------------------------------------------------------------------- 1 | # rendering table wraps in SELECT * 2 | 3 | Code 4 | out %>% sql_render() 5 | Output 6 | SELECT * 7 | FROM `test-sql-build` 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/sql.md: -------------------------------------------------------------------------------- 1 | # can format sql 2 | 3 | Code 4 | sql() 5 | Output 6 | [empty] 7 | 8 | --- 9 | 10 | Code 11 | sql(a = "x", "y") 12 | Output 13 | x AS a 14 | y 15 | 16 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/table-name.md: -------------------------------------------------------------------------------- 1 | # table_path possess key methods 2 | 3 | Code 4 | name <- table_path(c("x", "y", "z")) 5 | name 6 | Output 7 | x, y, z 8 | 9 | # can check for table name 10 | 11 | Code 12 | foo(1) 13 | Condition 14 | Error in `foo()`: 15 | ! `y` must be a , not a string. 16 | i This is an internal error that was detected in the dbplyr package. 17 | Please report it at with a reprex () and the full backtrace. 18 | 19 | # as_table_path validates its inputs 20 | 21 | Code 22 | as_table_path("x") 23 | Condition 24 | Error in `as_table_path()`: 25 | ! `con` is absent but must be supplied. 26 | Code 27 | as_table_path(c("x", "y"), con) 28 | Condition 29 | Error: 30 | ! `c("x", "y")` must be a single string, not a character vector. 31 | Code 32 | as_table_path(1, con) 33 | Condition 34 | Error in `as_table_path()`: 35 | ! `1` uses unknown specification for table name 36 | Code 37 | as_table_path(I(1), con) 38 | Condition 39 | Error: 40 | ! `I(1)` must be a single string, not the number 1. 41 | 42 | # as_table_path warns when using sql 43 | 44 | Code 45 | as_table_path(sql("x"), con) 46 | Condition 47 | Warning: 48 | `sql("x")` uses SQL where a table identifier is expected. 49 | i If you want to use a literal (unquoted) identifier use `I()` instead. 50 | Output 51 | x 52 | 53 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/tbl-lazy.md: -------------------------------------------------------------------------------- 1 | # argument src is deprecated 2 | 3 | Code 4 | tbl_lazy(mtcars, src = simulate_sqlite()) 5 | Condition 6 | Error in `tbl_lazy()`: 7 | ! `...` must be empty. 8 | x Problematic argument: 9 | * src = simulate_sqlite() 10 | 11 | # cannot convert tbl_lazy to data.frame 12 | 13 | Code 14 | as.data.frame(tbl_lazy(mtcars, con = simulate_sqlite())) 15 | Condition 16 | Error in `as.data.frame()`: 17 | ! Can not coerce to 18 | 19 | # has print method 20 | 21 | Code 22 | tbl_lazy(mtcars) 23 | Output 24 | 25 | SELECT * 26 | FROM `df` 27 | 28 | # names() inform that they aren't meant to be used 29 | 30 | Code 31 | names(lazy_frame(x = 1)) 32 | Message 33 | ! The `names()` method of is for internal use only. 34 | i Did you mean `colnames()`? 35 | Output 36 | [1] "lazy_query" "src" 37 | 38 | # $ aborts when not used with src or lazy_query 39 | 40 | The `$` method of is for internal use only. 41 | i Use `dplyr::pull()` to get the values in a column. 42 | 43 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/tbl-sql.md: -------------------------------------------------------------------------------- 1 | # sql tbl can be printed 2 | 3 | Code 4 | mf2 5 | Output 6 | # Source: SQL [?? x 2] 7 | # Database: sqlite ?.?.? [:memory:] 8 | x y 9 | 10 | 1 1 3 11 | 2 2 2 12 | 3 3 1 13 | 14 | # useful error if missing I() 15 | 16 | Code 17 | tbl(src_memdb(), "foo.bar") 18 | Condition 19 | Error in `tbl_sql()`: 20 | ! Failed to find table `foo.bar`. 21 | i Did you mean `from = I("foo.bar")`? 22 | Caused by error in `db_query_fields.DBIConnection()`: 23 | ! Can't query fields. 24 | i Using SQL: SELECT * FROM `foo.bar` AS `q05` WHERE (0 = 1) 25 | Caused by error: 26 | ! no such table: foo.bar 27 | 28 | # check_from is deprecated 29 | 30 | Code 31 | out <- tbl(con, "x", check_from = FALSE) 32 | Condition 33 | Warning: 34 | The `check_from` argument of `tbl_sql()` is deprecated as of dbplyr 2.5.0. 35 | 36 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/tidyeval.md: -------------------------------------------------------------------------------- 1 | # old arguments are defunct 2 | 3 | Code 4 | partial_eval(quote(x), vars = c("x", "y")) 5 | Condition 6 | Error: 7 | ! The `vars` argument of `partial_eval()` was deprecated in dbplyr 2.1.2 and is now defunct. 8 | Code 9 | partial_eval(quote(x), data = c("x", "y")) 10 | Condition 11 | Error: 12 | ! The `data` argument of `partial_eval()` must be a lazy frame as of dbplyr 2.1.2. 13 | 14 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/translate-sql-cut.md: -------------------------------------------------------------------------------- 1 | # works with labels a character vector 2 | 3 | Code 4 | (expect_error(test_translate_sql(cut(x, 1:3, labels = c("a", "b", "c"))))) 5 | Output 6 | 7 | Error in `cut()`: 8 | ! Can't recycle `labels` (size 3) to size 2. 9 | 10 | # cut checks arguments 11 | 12 | Code 13 | (expect_error(test_translate_sql(cut(x, 1)))) 14 | Output 15 | 16 | Error in `cut()`: 17 | ! `breaks` must have at least two values. 18 | Code 19 | (expect_error(test_translate_sql(cut(x, c(1, 1))))) 20 | Output 21 | 22 | Error in `cut()`: 23 | ! `breaks` are not unique. 24 | Code 25 | (expect_error(test_translate_sql(cut(x, c(1, 2, NA))))) 26 | Output 27 | 28 | Error in `cut()`: 29 | ! `breaks` values must not be missing. 30 | 31 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/translate-sql-helpers.md: -------------------------------------------------------------------------------- 1 | # warns informatively with unsupported function 2 | 3 | Code 4 | sql_not_supported("cor")() 5 | Condition 6 | Error: 7 | ! `cor()` is not available in this SQL variant. 8 | 9 | # duplicates throw an error 10 | 11 | Code 12 | sql_translator(round = function(x) x, round = function(y) y) 13 | Condition 14 | Error in `sql_translator()`: 15 | ! Duplicate names in `sql_translator()` 16 | * round 17 | 18 | # output of print method for sql_variant is correct 19 | 20 | Code 21 | sql_variant(sim_trans, sim_trans, sim_trans) 22 | Output 23 | 24 | scalar: + 25 | aggregate: + 26 | window: + 27 | 28 | # win_rank() is accepted by the sql_translator 29 | 30 | Code 31 | sql_variant(sql_translator(test = win_rank("test"))) 32 | Output 33 | 34 | scalar: test 35 | 36 | # sql_prefix checks arguments 37 | 38 | Code 39 | sin_db(sin(1, 2)) 40 | Condition 41 | Error in `sin()`: 42 | ! 2 arguments passed to 'sin' which requires 1 43 | 44 | --- 45 | 46 | Code 47 | sin_db(sin(a = 1)) 48 | Condition 49 | Error in `sin()`: 50 | ! supplied argument name 'a' does not match 'x' 51 | 52 | # runif is translated 53 | 54 | Code 55 | test_translate_sql(runif(2)) 56 | Condition 57 | Error in `sql_runif()`: 58 | ! Only `n = n()` is supported. 59 | 60 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/translate-sql-quantile.md: -------------------------------------------------------------------------------- 1 | # quantile and median don't change without warning 2 | 3 | Code 4 | test_translate_sql(quantile(x, 0.75, na.rm = TRUE), window = FALSE) 5 | Output 6 | PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY `x`) 7 | 8 | --- 9 | 10 | Code 11 | test_translate_sql(quantile(x, 0.75, na.rm = TRUE), vars_group = "g") 12 | Output 13 | PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY `x`) OVER (PARTITION BY `g`) 14 | 15 | --- 16 | 17 | Code 18 | test_translate_sql(median(x, na.rm = TRUE), window = FALSE) 19 | Output 20 | PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY `x`) 21 | 22 | --- 23 | 24 | Code 25 | test_translate_sql(median(x, na.rm = TRUE), vars_group = "g") 26 | Output 27 | PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY `x`) OVER (PARTITION BY `g`) 28 | 29 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/translate-sql-string.md: -------------------------------------------------------------------------------- 1 | # sql_substr works as expected 2 | 3 | Code 4 | substr("test") 5 | Condition 6 | Error in `substr()`: 7 | ! `start` must be a whole number, not absent. 8 | 9 | --- 10 | 11 | Code 12 | substr("test", 0) 13 | Condition 14 | Error in `substr()`: 15 | ! `stop` must be a whole number, not absent. 16 | 17 | --- 18 | 19 | Code 20 | substr("test", "x", 1) 21 | Condition 22 | Error in `substr()`: 23 | ! `start` must be a whole number, not the string "x". 24 | 25 | --- 26 | 27 | Code 28 | substr("test", 1, "x") 29 | Condition 30 | Error in `substr()`: 31 | ! `stop` must be a whole number, not the string "x". 32 | 33 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/translate-sql.md: -------------------------------------------------------------------------------- 1 | # dplyr.strict_sql = TRUE prevents auto conversion 2 | 3 | Code 4 | test_translate_sql(blah(x)) 5 | Condition 6 | Error in `blah()`: 7 | ! Don't know how to translate `blah()` 8 | Code 9 | test_translate_sql(x %blah% y) 10 | Condition 11 | Error in `x %blah% y`: 12 | ! Don't know how to translate `%blah%` 13 | 14 | # namespace calls are translated 15 | 16 | Code 17 | test_translate_sql(NOSUCHPACKAGE::foo()) 18 | Condition 19 | Error: 20 | ! There is no package called NOSUCHPACKAGE 21 | Code 22 | test_translate_sql(dbplyr::NOSUCHFUNCTION()) 23 | Condition 24 | Error: 25 | ! "NOSUCHFUNCTION" is not an exported object from dbplyr 26 | Code 27 | test_translate_sql(base::abbreviate(x)) 28 | Condition 29 | Error in `base::abbreviate()`: 30 | ! No known SQL translation 31 | 32 | --- 33 | 34 | Code 35 | lz %>% mutate(x = NOSUCHPACKAGE::foo()) 36 | Condition 37 | Error: 38 | ! There is no package called NOSUCHPACKAGE 39 | Code 40 | lz %>% mutate(x = dbplyr::NOSUCHFUNCTION()) 41 | Condition 42 | Error: 43 | ! "NOSUCHFUNCTION" is not an exported object from dbplyr 44 | Code 45 | lz %>% mutate(x = base::abbreviate(x)) 46 | Condition 47 | Error in `base::abbreviate()`: 48 | ! No known SQL translation 49 | 50 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-compute.md: -------------------------------------------------------------------------------- 1 | # index fails if columns are missing 2 | 3 | Code 4 | (expect_error(compute(mf, indexes = list(c("y", "x", "z"), "a")))) 5 | Output 6 | 7 | Error in `compute()`: 8 | ! All columns specified through `indexes` must exist in `x`. 9 | i The following columns are missing from `indexes`: y, z, and a. 10 | Code 11 | (expect_error(compute(mf, unique_indexes = list(c("y", "x", "z"), "a")))) 12 | Output 13 | 14 | Error in `compute()`: 15 | ! All columns specified through `unique_indexes` must exist in `x`. 16 | i The following columns are missing from `unique_indexes`: y, z, and a. 17 | 18 | # compute can handle schema 19 | 20 | Code 21 | df %>% compute(name = in_schema("main", "db1"), temporary = FALSE) 22 | Condition 23 | Error in `db_compute()`: 24 | ! Can't copy query to table `main`.`db1`. 25 | Caused by error in `db_save_query.DBIConnection()`: 26 | ! Can't save query to table `main`.`db1`. 27 | i Using SQL: CREATE TABLE `main`.`db1` AS SELECT * FROM `dbplyr_{tmp}` 28 | Caused by error: 29 | ! dummy DBI error 30 | 31 | # collect() handles DBI error 32 | 33 | Code 34 | (expect_error(mf %>% mutate(a = sql("invalid sql")) %>% collect())) 35 | Output 36 | 37 | Error in `collect()`: 38 | ! Failed to collect lazy table. 39 | Caused by error: 40 | ! dummy DBI error 41 | 42 | # compute(temporary = FALSE) without a name is deprecated 43 | 44 | The `name` argument of `compute()` must be provided when `temporary = FALSE` as of dbplyr 2.3.3. 45 | 46 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-count.md: -------------------------------------------------------------------------------- 1 | # generates expected SQL for common situations 2 | 3 | Code 4 | db %>% count(g) 5 | Output 6 | 7 | SELECT `g`, COUNT(*) AS `n` 8 | FROM `df` 9 | GROUP BY `g` 10 | 11 | --- 12 | 13 | Code 14 | db %>% count(g, wt = x) 15 | Output 16 | 17 | SELECT `g`, SUM(`x`) AS `n` 18 | FROM `df` 19 | GROUP BY `g` 20 | 21 | --- 22 | 23 | Code 24 | db %>% count(g, sort = TRUE) 25 | Output 26 | 27 | SELECT `g`, COUNT(*) AS `n` 28 | FROM `df` 29 | GROUP BY `g` 30 | ORDER BY `n` DESC 31 | 32 | --- 33 | 34 | Code 35 | db %>% add_count(g, sort = TRUE) 36 | Output 37 | 38 | SELECT `df`.*, COUNT(*) OVER (PARTITION BY `g`) AS `n` 39 | FROM `df` 40 | ORDER BY `n` DESC 41 | 42 | --- 43 | 44 | Code 45 | db %>% group_by(g) %>% add_count() 46 | Output 47 | 48 | SELECT `df`.*, COUNT(*) OVER (PARTITION BY `g`) AS `n` 49 | FROM `df` 50 | 51 | # .drop is not supported 52 | 53 | Code 54 | lazy_frame(g = 1) %>% add_count(.drop = TRUE) 55 | Condition 56 | Error in `add_count()`: 57 | ! Argument `.drop` isn't supported on database backends. 58 | 59 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-distinct.md: -------------------------------------------------------------------------------- 1 | # distinct() produces optimized SQL 2 | 3 | Code 4 | (out <- lf %>% head(2) %>% distinct(x, y)) 5 | Output 6 | 7 | SELECT DISTINCT `q01`.* 8 | FROM ( 9 | SELECT `df`.* 10 | FROM `df` 11 | LIMIT 2 12 | ) AS `q01` 13 | 14 | # distinct respects window_order when .keep_all is TRUE 15 | 16 | Code 17 | lf %>% window_order(desc(y)) %>% distinct(x, .keep_all = TRUE) 18 | Output 19 | 20 | SELECT `x`, `y` 21 | FROM ( 22 | SELECT 23 | `df`.*, 24 | ROW_NUMBER() OVER (PARTITION BY `x` ORDER BY `y` DESC) AS `col01` 25 | FROM `df` 26 | ) AS `q01` 27 | WHERE (`col01` = 1) 28 | 29 | # distinct uses dummy window order when .keep_all is TRUE and no order is used 30 | 31 | Code 32 | lf %>% distinct(x, .keep_all = TRUE) 33 | Output 34 | 35 | SELECT `x`, `y` 36 | FROM ( 37 | SELECT `df`.*, ROW_NUMBER() OVER (PARTITION BY `x` ORDER BY `x`) AS `col01` 38 | FROM `df` 39 | ) AS `q01` 40 | WHERE (`col01` = 1) 41 | 42 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-do.md: -------------------------------------------------------------------------------- 1 | # unnamed results must be data frames 2 | 3 | Code 4 | mf %>% do(nrow(.)) 5 | Condition 6 | Error in `label_output_dataframe()`: 7 | ! Results must be data frames 8 | Problems at positions 1 and 2 9 | 10 | # named argument become list columns 11 | 12 | Code 13 | mf %>% do(nrow = nrow(.), ncol(.)) 14 | Condition 15 | Error in `named_args()`: 16 | ! Arguments to `do()` must either be all named or all unnamed 17 | 18 | --- 19 | 20 | Code 21 | mf %>% do(nrow(.), ncol(.)) 22 | Condition 23 | Error in `named_args()`: 24 | ! Can only supply single unnamed argument to `do()` 25 | 26 | --- 27 | 28 | Code 29 | mf %>% do(.f = nrow) 30 | Condition 31 | Error in `named_args()`: 32 | ! `do()` syntax changed in dplyr 0.2. Please see documentation for details 33 | 34 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-group_by.md: -------------------------------------------------------------------------------- 1 | # errors about add argument 2 | 3 | Code 4 | gf <- mf %>% group_by(x) %>% group_by(y, add = TRUE) 5 | Condition 6 | Error: 7 | ! The `add` argument of `group_by()` was deprecated in dplyr 1.0.0 and is now defunct. 8 | i Please use the `.add` argument instead. 9 | 10 | # errors for .drop = FALSE 11 | 12 | Code 13 | lazy_frame(x = 1:3, y = 1:3) %>% group_by(y, .drop = FALSE) 14 | Condition 15 | Error in `group_by()`: 16 | ! `.drop = FALSE` isn't supported on database backends. 17 | i It must be TRUE instead. 18 | 19 | # informative errors for missing variables 20 | 21 | Code 22 | (expect_error(lazy_frame(x = 1:3) %>% group_by(y))) 23 | Output 24 | 25 | Error in `group_by()`: 26 | i In argument: `y` 27 | Caused by error: 28 | ! Object `y` not found. 29 | 30 | # group_by() produces nice error messages 31 | 32 | Code 33 | lf %>% group_by(z = non_existent + 1) 34 | Condition 35 | Error in `group_by()`: 36 | i In argument: `z = non_existent + 1` 37 | Caused by error: 38 | ! Object `non_existent` not found. 39 | Code 40 | lf %>% group_by(across(non_existent)) 41 | Condition 42 | Error in `group_by()`: 43 | i In argument: `across(non_existent)` 44 | Caused by error in `across()`: 45 | ! Can't select columns that don't exist. 46 | x Column `non_existent` doesn't exist. 47 | 48 | # ungroup() produces nice error messages 49 | 50 | Code 51 | lazy_frame(x = 1) %>% ungroup(non_existent) 52 | Condition 53 | Error in `ungroup()`: 54 | ! Can't select columns that don't exist. 55 | x Column `non_existent` doesn't exist. 56 | 57 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-pull.md: -------------------------------------------------------------------------------- 1 | # ungroup() produces nice error messages 2 | 3 | Code 4 | memdb_frame(x = 1) %>% pull(non_existent) 5 | Condition 6 | Error in `pull()`: 7 | Caused by error: 8 | ! object 'non_existent' not found 9 | Code 10 | memdb_frame(x = 1) %>% pull("non_existent") 11 | Condition 12 | Error in `pull()`: 13 | ! Can't extract columns that don't exist. 14 | x Column `non_existent` doesn't exist. 15 | Code 16 | memdb_frame(x = 1) %>% pull(1000) 17 | Condition 18 | Error in `pull()`: 19 | ! Can't extract columns past the end. 20 | i Location 1000 doesn't exist. 21 | i There is only 1 column. 22 | Code 23 | memdb_frame(x = 1) %>% pull(x, "name_non_existent") 24 | Condition 25 | Error in `pull()`: 26 | ! Can't extract columns that don't exist. 27 | x Column `name_non_existent` doesn't exist. 28 | 29 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-set-ops.md: -------------------------------------------------------------------------------- 1 | # can combine multiple union in one query 2 | 3 | Code 4 | lf1 %>% union_all(lf2) %>% union(lf3) 5 | Output 6 | 7 | SELECT `lf1`.*, NULL AS `z` 8 | FROM `lf1` 9 | 10 | UNION ALL 11 | 12 | SELECT `q01`.*, NULL AS `z` 13 | FROM ( 14 | SELECT NULL AS `x`, `lf2`.* 15 | FROM `lf2` 16 | ) AS `q01` 17 | 18 | UNION 19 | 20 | SELECT NULL AS `x`, NULL AS `y`, `lf3`.* 21 | FROM `lf3` 22 | 23 | --- 24 | 25 | Code 26 | lf1 %>% union_all(lf2) %>% union(lf3) %>% left_join(lf1, by = "x") %>% 27 | show_query(sql_options = sql_options(cte = TRUE)) 28 | Output 29 | 30 | WITH `q01` AS ( 31 | SELECT `lf1`.*, NULL AS `z` 32 | FROM `lf1` 33 | ), 34 | `q02` AS ( 35 | SELECT NULL AS `x`, `lf2`.* 36 | FROM `lf2` 37 | ), 38 | `q03` AS ( 39 | SELECT `q01`.*, NULL AS `z` 40 | FROM `q02` AS `q01` 41 | ), 42 | `q04` AS ( 43 | SELECT NULL AS `x`, NULL AS `y`, `lf3`.* 44 | FROM `lf3` 45 | ), 46 | `q05` AS ( 47 | SELECT * 48 | FROM `q01` 49 | 50 | UNION ALL 51 | 52 | SELECT * 53 | FROM `q03` 54 | 55 | UNION 56 | 57 | SELECT * 58 | FROM `q04` 59 | ) 60 | SELECT `LHS`.`x` AS `x`, `LHS`.`y` AS `y.x`, `z`, `lf1`.`y` AS `y.y` 61 | FROM `q05` AS `LHS` 62 | LEFT JOIN `lf1` 63 | ON (`LHS`.`x` = `lf1`.`x`) 64 | 65 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-uncount.md: -------------------------------------------------------------------------------- 1 | # symbols weights are dropped in output 2 | 3 | Code 4 | dbplyr_uncount(df, w) %>% show_query() 5 | Output 6 | 7 | SELECT `x` 8 | FROM `test` 9 | INNER JOIN ( 10 | SELECT CAST(`..dbplyr_row_id` AS INTEGER) AS `..dbplyr_row_id` 11 | FROM ( 12 | SELECT NULL AS `..dbplyr_row_id` 13 | WHERE (0 = 1) 14 | 15 | UNION ALL 16 | 17 | VALUES (1) 18 | ) AS `values_table` 19 | ) AS `RHS` 20 | ON (`RHS`.`..dbplyr_row_id` <= `test`.`w`) 21 | 22 | --- 23 | 24 | Code 25 | df %>% mutate(w = w + 1) %>% dbplyr_uncount(w) %>% show_query() 26 | Output 27 | 28 | SELECT `x` 29 | FROM ( 30 | SELECT `x`, `w` + 1.0 AS `w` 31 | FROM `test` 32 | ) AS `LHS` 33 | INNER JOIN ( 34 | SELECT CAST(`..dbplyr_row_id` AS INTEGER) AS `..dbplyr_row_id` 35 | FROM ( 36 | SELECT NULL AS `..dbplyr_row_id` 37 | WHERE (0 = 1) 38 | 39 | UNION ALL 40 | 41 | VALUES (1), (2) 42 | ) AS `values_table` 43 | ) AS `RHS` 44 | ON (`RHS`.`..dbplyr_row_id` <= `LHS`.`w`) 45 | 46 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/verb-window.md: -------------------------------------------------------------------------------- 1 | # window_order errors for data frame 2 | 3 | Code 4 | (expect_error(window_order(data.frame(x = 1)))) 5 | Output 6 | 7 | Error in `window_order()`: 8 | ! `.data` must be a , not a data frame. 9 | i Did you mean to use `arrange()` instead? 10 | Code 11 | (expect_error(window_order("a"))) 12 | Output 13 | 14 | Error in `window_order()`: 15 | ! `.data` must be a , not a string. 16 | 17 | # window_order only accepts variables 18 | 19 | Code 20 | (expect_error(window_order(lf, x + y))) 21 | Output 22 | 23 | Error in `window_order()`: 24 | ! Each element of `...` must be a single column name or a column wrapped in `desc()`. 25 | x Element 1 is `x + y`. 26 | 27 | # window order works afer renaming variable 28 | 29 | Code 30 | lazy_frame(x = 1, y = 1) %>% window_order(y) %>% rename(y2 = y) %>% mutate( 31 | x_cum = cumsum(x)) 32 | Output 33 | 34 | SELECT 35 | `q01`.*, 36 | SUM(`x`) OVER (ORDER BY `y2` ROWS UNBOUNDED PRECEDING) AS `x_cum` 37 | FROM ( 38 | SELECT `x`, `y` AS `y2` 39 | FROM `df` 40 | ) AS `q01` 41 | Code 42 | lazy_frame(x = 1, y = 1) %>% rename(y2 = y) %>% window_order(y2) %>% mutate( 43 | x_cum = cumsum(x)) 44 | Output 45 | 46 | SELECT 47 | `q01`.*, 48 | SUM(`x`) OVER (ORDER BY `y2` ROWS UNBOUNDED PRECEDING) AS `x_cum` 49 | FROM ( 50 | SELECT `x`, `y` AS `y2` 51 | FROM `df` 52 | ) AS `q01` 53 | 54 | # window_frame errors for data frame 55 | 56 | Code 57 | (expect_error(window_frame(data.frame(x = 1)))) 58 | Output 59 | 60 | Error in `window_frame()`: 61 | ! `.data` must be a , not a . 62 | 63 | -------------------------------------------------------------------------------- /tests/testthat/helper-src.R: -------------------------------------------------------------------------------- 1 | on_gha <- function() identical(Sys.getenv("GITHUB_ACTIONS"), "true") 2 | on_cran <- function() !identical(Sys.getenv("NOT_CRAN"), "true") 3 | 4 | if (test_srcs$length() == 0) { 5 | 6 | test_register_con("sqlite", RSQLite::SQLite(), ":memory:") 7 | 8 | if (identical(Sys.getenv("GITHUB_POSTGRES"), "true")) { 9 | test_register_con("postgres", RPostgres::Postgres(), 10 | dbname = "test", 11 | user = "postgres", 12 | password = "password", 13 | host = "127.0.0.1" 14 | ) 15 | } else if (identical(Sys.getenv("GITHUB_MSSQL"), "true")) { 16 | test_register_con("mssql", odbc::odbc(), 17 | driver = "ODBC Driver 17 for SQL Server", 18 | database = "test", 19 | uid = "SA", 20 | pwd = "Password12", 21 | server = "localhost", 22 | port = 1433 23 | ) 24 | } else if (on_gha() || on_cran()) { 25 | # Only test with sqlite 26 | } else { 27 | test_register_con("MariaDB", RMariaDB::MariaDB(), 28 | dbname = "test", 29 | host = "localhost", 30 | username = Sys.getenv("USER") 31 | ) 32 | test_register_con("postgres", RPostgres::Postgres(), 33 | dbname = "test", 34 | host = "localhost", 35 | user = "" 36 | ) 37 | } 38 | } 39 | 40 | local_sqlite_con_with_aux <- function(envir = parent.frame()) { 41 | tmp <- tempfile() 42 | 43 | con <- withr::local_db_connection( 44 | DBI::dbConnect(RSQLite::SQLite(), ":memory:"), 45 | .local_envir = envir 46 | ) 47 | DBI::dbExecute(con, paste0("ATTACH '", tmp, "' AS aux")) 48 | 49 | con 50 | } 51 | 52 | snap_transform_dbi <- function(x) { 53 | x <- gsub("dbplyr_[a-zA-Z0-9]+", "dbplyr_{tmp}", x) 54 | 55 | # use the last line matching this in case of multiple chained errors 56 | caused_by <- which(x == "Caused by error:") 57 | if (length(caused_by) == 0) { 58 | return(x) 59 | } 60 | 61 | dbi_line_id <- max(caused_by) 62 | 63 | n <- length(x) 64 | x <- x[-seq2(dbi_line_id + 1, n)] 65 | c(x, "! dummy DBI error") 66 | } 67 | -------------------------------------------------------------------------------- /tests/testthat/test-backend-hana.R: -------------------------------------------------------------------------------- 1 | test_that("custom string translations", { 2 | local_con(simulate_hana()) 3 | 4 | expect_snapshot(test_translate_sql(paste0("a", "b"))) 5 | expect_snapshot(test_translate_sql(paste("a", "b"))) 6 | 7 | expect_snapshot(test_translate_sql(substr(x, 2, 4))) 8 | expect_snapshot(test_translate_sql(substring(x, 2, 4))) 9 | expect_snapshot(test_translate_sql(str_sub(x, 2, -2))) 10 | }) 11 | 12 | test_that("copy_inline uses UNION ALL", { 13 | con <- simulate_hana() 14 | y <- tibble::tibble(id = 1L, arr = "{1,2,3}") 15 | 16 | types <- c(id = "bigint", arr = "integer[]") 17 | expect_snapshot({ 18 | copy_inline(con, y %>% slice(0)) %>% remote_query() 19 | copy_inline(con, y) %>% remote_query() 20 | 21 | # with `types` 22 | copy_inline(con, y %>% slice(0), types = types) %>% remote_query() 23 | copy_inline(con, y, types = types) %>% remote_query() 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /tests/testthat/test-backend-hive.R: -------------------------------------------------------------------------------- 1 | test_that("custom scalar & string functions translated correctly", { 2 | local_con(simulate_hive()) 3 | 4 | expect_equal(test_translate_sql(bitwShiftL(x, 2L)), sql("SHIFTLEFT(`x`, 2)")) 5 | expect_equal(test_translate_sql(bitwShiftR(x, 2L)), sql("SHIFTRIGHT(`x`, 2)")) 6 | expect_equal(test_translate_sql(cot(x)), sql("1.0 / TAN(`x`)")) 7 | expect_equal(test_translate_sql(str_replace_all(x, "old", "new")), sql("REGEXP_REPLACE(`x`, 'old', 'new')")) 8 | expect_equal(test_translate_sql(median(x, na.rm = TRUE)), sql("PERCENTILE(`x`, 0.5) OVER ()")) 9 | }) 10 | 11 | test_that("generates custom sql", { 12 | con <- simulate_hive() 13 | expect_snapshot(sql_table_analyze(con, in_schema("schema", "tbl"))) 14 | 15 | expect_equal( 16 | translate_sql(last(x, na_rm = TRUE), vars_order = "a", con = con), 17 | sql("LAST_VALUE(`x`, TRUE) OVER (ORDER BY `a` ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)") 18 | ) 19 | 20 | lf <- lazy_frame(tibble(x = 1), con = con) 21 | expect_snapshot(union_all(lf, lf)) 22 | }) 23 | -------------------------------------------------------------------------------- /tests/testthat/test-backend-impala.R: -------------------------------------------------------------------------------- 1 | test_that("custom scalar functions translated correctly", { 2 | local_con(simulate_impala()) 3 | 4 | expect_equal(test_translate_sql(as.Date(x)), sql("CAST(`x` AS VARCHAR(10))")) 5 | expect_equal(test_translate_sql(ceiling(x)), sql("CEIL(`x`)")) 6 | }) 7 | 8 | test_that("custom bitwise operations translated correctly", { 9 | local_con(simulate_impala()) 10 | 11 | expect_equal(test_translate_sql(bitwNot(x)), sql("BITNOT(`x`)")) 12 | expect_equal(test_translate_sql(bitwAnd(x, 128L)), sql("BITAND(`x`, 128)")) 13 | expect_equal(test_translate_sql(bitwOr(x, 128L)), sql("BITOR(`x`, 128)")) 14 | expect_equal(test_translate_sql(bitwXor(x, 128L)), sql("BITXOR(`x`, 128)")) 15 | expect_equal(test_translate_sql(bitwShiftL(x, 2L)), sql("SHIFTLEFT(`x`, 2)")) 16 | expect_equal(test_translate_sql(bitwShiftR(x, 2L)), sql("SHIFTRIGHT(`x`, 2)")) 17 | }) 18 | 19 | test_that("generates custom sql", { 20 | con <- simulate_impala() 21 | 22 | expect_snapshot(sql_table_analyze(con, in_schema("schema", "tbl"))) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/test-backend-odbc.R: -------------------------------------------------------------------------------- 1 | test_that("custom scalar translated correctly", { 2 | local_con(simulate_odbc()) 3 | 4 | expect_equal(test_translate_sql(as.numeric(x)), sql("CAST(`x` AS DOUBLE)")) 5 | expect_equal(test_translate_sql(as.double(x)), sql("CAST(`x` AS DOUBLE)")) 6 | expect_equal(test_translate_sql(as.integer(x)), sql("CAST(`x` AS INT)")) 7 | expect_equal(test_translate_sql(as.character(x)), sql("CAST(`x` AS STRING)")) 8 | }) 9 | 10 | test_that("custom aggregators translated correctly", { 11 | local_con(simulate_odbc()) 12 | 13 | expect_equal( 14 | test_translate_sql(sd(x, na.rm = TRUE), window = FALSE), 15 | sql("STDDEV_SAMP(`x`)") 16 | ) 17 | }) 18 | 19 | test_that("custom window functions translated correctly", { 20 | local_con(simulate_odbc()) 21 | 22 | expect_equal( 23 | test_translate_sql(sd(x, na.rm = TRUE)), 24 | sql("STDDEV_SAMP(`x`) OVER ()") 25 | ) 26 | }) 27 | -------------------------------------------------------------------------------- /tests/testthat/test-backend-postgres-old.R: -------------------------------------------------------------------------------- 1 | test_that("RPostgreSQL backend", { 2 | skip_if_not(identical(Sys.getenv("GITHUB_POSTGRES"), "true")) 3 | 4 | src <- withr::local_db_connection( 5 | DBI::dbConnect( 6 | RPostgreSQL::PostgreSQL(), 7 | dbname = "test", 8 | user = "postgres", 9 | password = "password", 10 | host = "127.0.0.1" 11 | ) 12 | ) 13 | 14 | suppressWarnings( 15 | copy_to(src, mtcars, "mtcars", overwrite = TRUE, temporary = FALSE) 16 | ) 17 | withr::defer(DBI::dbRemoveTable(src, "mtcars")) 18 | 19 | expect_identical(colnames(tbl(src, "mtcars")), colnames(mtcars)) 20 | 21 | src_cyl <- tbl(src, "mtcars") %>% select(cyl) %>% collect() 22 | expect_identical(src_cyl$cyl, mtcars$cyl) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/test-backend-spark-sql.R: -------------------------------------------------------------------------------- 1 | test_that("custom clock functions translated correctly", { 2 | local_con(simulate_spark_sql()) 3 | expect_equal(test_translate_sql(add_years(x, 1)), sql("ADD_MONTHS(`x`, 1.0 * 12.0)")) 4 | expect_equal(test_translate_sql(add_days(x, 1)), sql("DATE_ADD(`x`, 1.0)")) 5 | expect_error( 6 | test_translate_sql(add_days(x, 1, "dots", "must", "be empty")), 7 | class = "rlib_error_dots_nonempty" 8 | ) 9 | expect_equal(test_translate_sql(date_build(2020, 1, 1)), sql("MAKE_DATE(2020.0, 1.0, 1.0)")) 10 | expect_equal(test_translate_sql(date_build(year_column, 1L, 1L)), sql("MAKE_DATE(`year_column`, 1, 1)")) 11 | expect_equal(test_translate_sql(get_year(date_column)), sql("DATE_PART('YEAR', `date_column`)")) 12 | expect_equal(test_translate_sql(get_month(date_column)), sql("DATE_PART('MONTH', `date_column`)")) 13 | expect_equal(test_translate_sql(get_day(date_column)), sql("DATE_PART('DAY', `date_column`)")) 14 | expect_equal(test_translate_sql(date_count_between(date_column_1, date_column_2, "day")), 15 | sql("DATEDIFF(`date_column_2`, `date_column_1`)")) 16 | expect_snapshot( 17 | error = TRUE, 18 | test_translate_sql(date_count_between(date_column_1, date_column_2, "year")) 19 | ) 20 | expect_snapshot( 21 | error = TRUE, 22 | test_translate_sql(date_count_between(date_column_1, date_column_2, "day", n = 5)) 23 | ) 24 | }) 25 | 26 | test_that("difftime is translated correctly", { 27 | local_con(simulate_spark_sql()) 28 | expect_equal(test_translate_sql(difftime(start_date, end_date, units = "days")), sql("DATEDIFF(`end_date`, `start_date`)")) 29 | expect_equal(test_translate_sql(difftime(start_date, end_date)), sql("DATEDIFF(`end_date`, `start_date`)")) 30 | 31 | expect_snapshot( 32 | error = TRUE, 33 | test_translate_sql(difftime(start_date, end_date, units = "auto")) 34 | ) 35 | expect_snapshot( 36 | error = TRUE, 37 | test_translate_sql(difftime(start_date, end_date, tz = "UTC", units = "days")) 38 | ) 39 | }) 40 | -------------------------------------------------------------------------------- /tests/testthat/test-db-escape.R: -------------------------------------------------------------------------------- 1 | test_that("can translate raw to blob spec", { 2 | con <- simulate_dbi() 3 | 4 | expect_equal(sql_escape_raw(con, NULL), "NULL") 5 | expect_equal(sql_escape_raw(con, charToRaw("abc")), "X'616263'") 6 | }) 7 | -------------------------------------------------------------------------------- /tests/testthat/test-db-io.R: -------------------------------------------------------------------------------- 1 | test_that("db_copy_to() wraps DBI errors", { 2 | con <- local_sqlite_connection() 3 | local_db_table(con, data.frame(x = 1), "tmp") 4 | 5 | # error when creating unique index 6 | expect_snapshot( 7 | (expect_error( 8 | db_copy_to( 9 | con = con, 10 | table = "tmp2", 11 | values = data.frame(x = c(1, 1)), 12 | unique_indexes = list("x") 13 | ) 14 | )), 15 | transform = snap_transform_dbi 16 | ) 17 | }) 18 | 19 | test_that("db_copy_to() can overwrite a table", { 20 | con <- local_sqlite_connection() 21 | local_db_table(con, data.frame(x = 1), "tmp") 22 | 23 | # doesn't overwrite by default 24 | expect_snapshot( 25 | (expect_error( 26 | db_copy_to( 27 | con = con, 28 | table = "tmp", 29 | values = data.frame(x = c(1, 1)) 30 | ) 31 | )), 32 | transform = snap_transform_dbi 33 | ) 34 | 35 | db_copy_to( 36 | con = con, 37 | table = "tmp", 38 | values = data.frame(x = c(1, 1)), 39 | overwrite = TRUE 40 | ) 41 | expect_equal(DBI::dbReadTable(con, "tmp"), data.frame(x = c(1, 1))) 42 | }) 43 | 44 | test_that("db_save_query() can overwrite a table", { 45 | con <- local_sqlite_connection() 46 | local_db_table(con, data.frame(x = 1), "tmp") 47 | 48 | # doesn't overwrite by default 49 | expect_snapshot( 50 | (expect_error( 51 | db_save_query( 52 | con = con, 53 | sql = "SELECT 2 FROM tmp", 54 | name = "tmp" 55 | ) 56 | )), 57 | transform = snap_transform_dbi 58 | ) 59 | 60 | db_save_query( 61 | con = con, 62 | sql = sql("SELECT 2 AS x"), 63 | name = "tmp", 64 | overwrite = TRUE 65 | ) 66 | expect_equal(DBI::dbReadTable(con, "tmp"), data.frame(x = 2L)) 67 | }) 68 | -------------------------------------------------------------------------------- /tests/testthat/test-db-sql.R: -------------------------------------------------------------------------------- 1 | test_that("2nd edition uses sql methods", { 2 | reset_warning_verbosity("Test-edition") 3 | local_methods( 4 | db_analyze.Test = function(con, ...) abort("db_method") 5 | ) 6 | 7 | con <- structure(list(), class = c("Test", "DBIConnection")) 8 | expect_snapshot(expect_error(dbplyr_analyze(con), "db_method")) 9 | 10 | local_methods( 11 | dbplyr_edition.Test = function(con) 2, 12 | sql_table_analyze.Test = function(con, ...) abort("sql_method") 13 | ) 14 | expect_error(dbplyr_analyze(con), "sql_method") 15 | }) 16 | 17 | test_that("sql_query_rows() works", { 18 | expect_equal( 19 | sql_query_rows(simulate_dbi(), ident("abc")), 20 | sql("SELECT COUNT(*) FROM `abc` AS `master`") 21 | ) 22 | }) 23 | 24 | test_that("handles DBI error", { 25 | unique_subquery_name_reset() 26 | con <- local_sqlite_connection() 27 | 28 | expect_snapshot({ 29 | (expect_error(db_analyze(con, "tbl"))) 30 | (expect_error(db_create_index(con, "tbl", "col"))) 31 | 32 | (expect_error(db_explain(con, "invalid sql"))) 33 | (expect_error(db_query_fields(con, "does not exist"))) 34 | (expect_error(db_save_query(con, "invalid sql", "tbl"))) 35 | }, 36 | transform = snap_transform_dbi 37 | ) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-ident.R: -------------------------------------------------------------------------------- 1 | test_that("zero length inputs return correct clases", { 2 | expect_s3_class(ident(), "ident") 3 | }) 4 | 5 | test_that("ident quotes", { 6 | con <- simulate_dbi() 7 | x1 <- ident("x") 8 | 9 | expect_equal(escape(x1, con = con), sql('`x`')) 10 | expect_equal(as.sql(x1), x1) 11 | }) 12 | 13 | test_that("can format ident", { 14 | expect_snapshot(ident()) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-lazy-join-query.R: -------------------------------------------------------------------------------- 1 | test_that("lazy_semi_join_query() checks arguments", { 2 | by0 <- list(x = "x", y = "x", x_as = ident("LHS"), y_as = ident("RHS"), na_matches = "never") 3 | lmod <- purrr::list_modify 4 | 5 | my_lazy_semi_join_query <- function(x = lazy_frame(x = 1, y = 2)$lazy_query, 6 | y = lazy_frame(x = 1, z = 2)$lazy_query, 7 | anti = FALSE, 8 | by = by0) { 9 | lazy_semi_join_query( 10 | x = x, 11 | y = y, 12 | vars = tibble(name = "x", var = "x"), 13 | anti = anti, 14 | by = by 15 | ) 16 | } 17 | 18 | expect_snapshot(error = TRUE, { 19 | (my_lazy_semi_join_query(x = lazy_frame(x = 1))) 20 | (my_lazy_semi_join_query(y = lazy_frame(x = 1))) 21 | }) 22 | 23 | expect_snapshot(error = TRUE, { 24 | (my_lazy_semi_join_query(by = lmod(by0, x = 1))) 25 | }) 26 | 27 | expect_snapshot(error = TRUE, { 28 | (my_lazy_semi_join_query(anti = NA)) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/testthat/test-lazy-select-query.R: -------------------------------------------------------------------------------- 1 | test_that("can print lazy_select_query", { 2 | lf <- lazy_frame(x = 1, y = 2) 3 | 4 | expect_snapshot( 5 | lazy_select_query( 6 | x = lf$lazy_query, 7 | select = quos( 8 | x_mean = mean(x), 9 | y2 = y 10 | ), 11 | where = quos(y > 1, x == y - 2), 12 | group_by = quos("x") 13 | ) 14 | ) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-pillar.R: -------------------------------------------------------------------------------- 1 | test_that("custom header", { 2 | expect_snapshot({ 3 | "Number of rows is shown" 4 | x <- memdb_frame(a = 1:3) %>% filter(a > 0) 5 | setup <- pillar::tbl_format_setup(x) 6 | tbl_format_header(x, setup)[[1]] 7 | 8 | "Number of rows still can't be shown if above 20" 9 | x <- memdb_frame(a = 1:21) %>% filter(a > 0) 10 | setup <- pillar::tbl_format_setup(x) 11 | tbl_format_header(x, setup)[[1]] 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /tests/testthat/test-query-semi-join.R: -------------------------------------------------------------------------------- 1 | test_that("print method doesn't change unexpectedly", { 2 | lf1 <- lazy_frame(x = 1, y = 2) 3 | lf2 <- lazy_frame(x = 1, z = 2) 4 | expect_snapshot( 5 | sql_build(semi_join(lf1, lf2 %>% filter(z == 2))) 6 | ) 7 | }) 8 | 9 | test_that("generated sql doesn't change unexpectedly", { 10 | lf <- lazy_frame(x = 1, y = 2) 11 | expect_snapshot(semi_join(lf, lf)) 12 | expect_snapshot(anti_join(lf, lf)) 13 | }) 14 | -------------------------------------------------------------------------------- /tests/testthat/test-query-set-op.R: -------------------------------------------------------------------------------- 1 | test_that("print method doesn't change unexpectedly", { 2 | lf1 <- lazy_frame(x = 1, y = 2, .name = "lf1") 3 | lf2 <- lazy_frame(x = 1, z = 2, .name = "lf2") 4 | lf3 <- lazy_frame(x = 1, z = 2, .name = "lf3") 5 | expect_snapshot(sql_build(union(lf1, lf2) %>% union_all(lf3))) 6 | }) 7 | 8 | test_that("generated sql doesn't change unexpectedly", { 9 | lf <- lazy_frame(x = 1, y = 2) 10 | expect_snapshot(union(lf, lf)) 11 | expect_snapshot(setdiff(lf, lf)) 12 | expect_snapshot(intersect(lf, lf)) 13 | 14 | expect_snapshot(union(lf, lf, all = TRUE)) 15 | expect_snapshot(setdiff(lf, lf, all = TRUE)) 16 | expect_snapshot(intersect(lf, lf, all = TRUE)) 17 | }) 18 | -------------------------------------------------------------------------------- /tests/testthat/test-schema.R: -------------------------------------------------------------------------------- 1 | test_that("can construct and print", { 2 | expect_snapshot(in_schema("schema", "table")) 3 | expect_snapshot(in_catalog("catalog", "schema", "table")) 4 | }) 5 | 6 | test_that("escaped as needed", { 7 | con <- simulate_dbi() 8 | expect_equal(as.sql(in_schema("s", "t"), con), ident_q("`s`.`t`")) 9 | expect_equal(as.sql(in_schema(sql("s"), sql("t")), con), ident_q("s.t")) 10 | expect_equal(as.sql(in_catalog("c", "s", "t"), con), ident_q("`c`.`s`.`t`")) 11 | expect_equal(as.sql(in_catalog(sql("c"), sql("s"), sql("t")), con), ident_q("c.s.t")) 12 | }) 13 | 14 | test_that("can copy and collect with schema or Id", { 15 | con <- local_sqlite_con_with_aux() 16 | df <- tibble(x = 1:10) 17 | 18 | db <- copy_to(con, df, in_schema("aux", "db1"), temporary = FALSE) 19 | expect_equal(collect(db), df) 20 | expect_equal(collect(filter(db, x < 2)), df[1, ]) 21 | 22 | db <- copy_to(con, df, Id(schema = "aux", table = "db2"), temporary = FALSE) 23 | expect_equal(collect(db), df) 24 | expect_equal(collect(filter(db, x < 2)), df[1, ]) 25 | }) 26 | 27 | test_that("quoted identifier correctly escaped", { 28 | con <- simulate_dbi() 29 | x2 <- ident_q('"x"') 30 | expect_equal(as.sql(x2), x2) 31 | expect_equal(escape(x2, con = con), sql('"x"')) 32 | 33 | expect_equal(sql_vector(ident_q(), collapse = NULL, con = con), sql()) 34 | expect_equal(sql_vector(ident_q(), parens = FALSE, collapse = "", con = con), sql("")) 35 | expect_equal(sql_vector(ident_q(), parens = TRUE, collapse = "", con = con), sql("()")) 36 | }) 37 | -------------------------------------------------------------------------------- /tests/testthat/test-sql-build.R: -------------------------------------------------------------------------------- 1 | test_that("rendering table wraps in SELECT *", { 2 | out <- copy_to_test("sqlite", tibble(x = 1), name = "test-sql-build") 3 | expect_snapshot(out %>% sql_render()) 4 | expect_equal(out %>% collect(), tibble(x = 1)) 5 | }) 6 | -------------------------------------------------------------------------------- /tests/testthat/test-sql-expr.R: -------------------------------------------------------------------------------- 1 | test_that("NULL becomes SQL NULL", { 2 | con <- simulate_dbi() 3 | expect_equal(sql_expr(NULL), sql("NULL")) 4 | }) 5 | 6 | test_that("atomic vectors are escaped", { 7 | con <- simulate_dbi() 8 | 9 | expect_equal(sql_expr(2, con = con), sql("2.0")) 10 | expect_equal(sql_expr("x", con = con), sql("'x'")) 11 | }) 12 | 13 | test_that("user infix functions have % stripped", { 14 | con <- simulate_dbi() 15 | 16 | expect_equal(sql_expr(x %like% y, con = con), sql("x LIKE y")) 17 | }) 18 | 19 | test_that("string function names are not quoted", { 20 | con <- simulate_dbi() 21 | 22 | f <- "foo" 23 | expect_equal(sql_expr((!!f)(), con = con), sql("FOO()")) 24 | }) 25 | 26 | test_that("correct number of parens", { 27 | con <- simulate_dbi() 28 | 29 | expect_equal(sql_expr((1L), con = con), sql("(1)")) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/testthat/test-sql.R: -------------------------------------------------------------------------------- 1 | test_that("can concatenate sql vector without supplying connection", { 2 | expect_equal(c(sql("x")), sql("x")) 3 | expect_equal(c(sql("x"), "x"), sql("x", "'x'")) 4 | expect_equal(c(ident("x")), sql("`x`")) 5 | }) 6 | 7 | test_that("can format sql", { 8 | expect_snapshot(sql()) 9 | expect_snapshot(sql(a = "x", "y")) 10 | }) 11 | -------------------------------------------------------------------------------- /tests/testthat/test-src_dbi.R: -------------------------------------------------------------------------------- 1 | test_that("tbl and src classes include connection class", { 2 | 3 | mf <- memdb_frame(x = 1, y = 2) 4 | expect_true(inherits(mf, "tbl_SQLiteConnection")) 5 | expect_true(inherits(mf$src, "src_SQLiteConnection")) 6 | }) 7 | 8 | test_that("generates S3 class based on S4 class name", { 9 | con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:") 10 | expect_equal( 11 | connection_s3_class(con), 12 | c("src_SQLiteConnection", "src_dbi", "src_sql", "src") 13 | ) 14 | 15 | on.exit(removeClass("Foo2")) 16 | on.exit(removeClass("Foo1")) 17 | 18 | Foo1 <- setClass("Foo1", contains = "DBIConnection") 19 | Foo2 <- setClass("Foo2", contains = "Foo1") 20 | expect_equal( 21 | connection_s3_class(Foo2()), 22 | c("src_Foo2", "src_Foo1", "src_dbi", "src_sql", "src") 23 | ) 24 | }) 25 | -------------------------------------------------------------------------------- /tests/testthat/test-tbl-lazy.R: -------------------------------------------------------------------------------- 1 | test_that("adds src class", { 2 | tb <- tbl_lazy(mtcars, con = simulate_sqlite()) 3 | expect_s3_class(tb, "tbl_SQLiteConnection") 4 | }) 5 | 6 | test_that("argument src is deprecated", { 7 | expect_snapshot(error = TRUE, tbl_lazy(mtcars, src = simulate_sqlite())) 8 | }) 9 | 10 | test_that("cannot convert tbl_lazy to data.frame", { 11 | expect_snapshot( 12 | error = TRUE, 13 | as.data.frame(tbl_lazy(mtcars, con = simulate_sqlite())) 14 | ) 15 | }) 16 | 17 | test_that("dim() works for tbl_lazy", { 18 | expect_equal(dim(tbl_lazy(mtcars)), c(NA, 11)) 19 | }) 20 | 21 | test_that("has print method", { 22 | expect_snapshot(tbl_lazy(mtcars)) 23 | }) 24 | 25 | test_that("support colwise variants", { 26 | mf <- memdb_frame(x = 1:5, y = factor(letters[1:5])) 27 | exp <- mf %>% collect() %>% mutate(y = as.character(y)) 28 | 29 | expect_message( 30 | mf1 <- dplyr::mutate_if(mf, is.factor, as.character), 31 | "on the first 100 rows" 32 | ) 33 | compare_tbl(mf1, exp) 34 | 35 | mf2 <- dplyr::mutate_at(mf, "y", as.character) 36 | compare_tbl(mf2, exp) 37 | }) 38 | 39 | test_that("base source of tbl_lazy is always 'df'", { 40 | out <- lazy_frame(x = 1, y = 5) %>% sql_build() 41 | expect_equal(out, base_query(table_path("`df`"))) 42 | }) 43 | 44 | test_that("names() inform that they aren't meant to be used", { 45 | expect_snapshot(names(lazy_frame(x = 1))) 46 | }) 47 | 48 | test_that("$ aborts when not used with src or lazy_query", { 49 | lf <- lazy_frame(x = 1) 50 | expect_no_error(lf$src) 51 | expect_no_error(lf$lazy_query) 52 | expect_snapshot_error(lf$x) 53 | }) 54 | -------------------------------------------------------------------------------- /tests/testthat/test-translate-sql-paste.R: -------------------------------------------------------------------------------- 1 | test_that("basic prefix operation", { 2 | local_con(simulate_dbi()) 3 | 4 | paste <- sql_paste("") 5 | x <- ident("x") 6 | y <- ident("y") 7 | 8 | expect_equal(paste(x), sql("CONCAT_WS('', `x`)")) 9 | expect_equal(paste(x, y), sql("CONCAT_WS('', `x`, `y`)")) 10 | expect_equal(paste(x, y, sep = " "), sql("CONCAT_WS(' ', `x`, `y`)")) 11 | }) 12 | 13 | test_that("basic infix operation", { 14 | local_con(simulate_dbi()) 15 | 16 | paste <- sql_paste_infix("", "&&", function(x) sql_expr(cast((!!x) %as% text))) 17 | x <- ident("x") 18 | y <- ident("y") 19 | 20 | expect_equal(paste(x), sql("CAST(`x` AS text)")) 21 | expect_equal(paste(x, y), sql("`x` && `y`")) 22 | expect_equal(paste(x, y, sep = " "), sql("`x` && ' ' && `y`")) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/test-translate-sql-quantile.R: -------------------------------------------------------------------------------- 1 | test_that("quantile and median don't change without warning", { 2 | local_con(simulate_dbi()) 3 | expect_snapshot(test_translate_sql(quantile(x, 0.75, na.rm = TRUE), window = FALSE)) 4 | expect_snapshot(test_translate_sql(quantile(x, 0.75, na.rm = TRUE), vars_group = "g")) 5 | expect_snapshot(test_translate_sql(median(x, na.rm = TRUE), window = FALSE)) 6 | expect_snapshot(test_translate_sql(median(x, na.rm = TRUE), vars_group = "g")) 7 | }) 8 | 9 | test_that("checks for invalid probs", { 10 | expect_error(check_probs("a"), "number") 11 | expect_error(check_probs(1:3), "vector") 12 | }) 13 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | test_that("Successful and not-successful commands are identified", { 2 | expect_true(succeeds("success")) 3 | expect_false(succeeds(x - 1, quiet = TRUE)) 4 | }) 5 | 6 | test_that("Returns error if no characters are passed", { 7 | expect_error(c_character(1, 2)) 8 | }) 9 | -------------------------------------------------------------------------------- /tests/testthat/test-verb-do.R: -------------------------------------------------------------------------------- 1 | test_that("ungrouped data collected first", { 2 | out <- memdb_frame(x = 1:2) %>% do(head(.)) 3 | expect_equal(out, tibble(x = 1:2)) 4 | }) 5 | 6 | test_that("named argument become list columns", { 7 | mf <- memdb_frame( 8 | g = rep(1:3, 1:3), 9 | x = 1:6 10 | ) %>% group_by(g) 11 | 12 | out <- mf %>% do(nrow = nrow(.), ncol = ncol(.)) 13 | expect_equal(out$nrow, list(1, 2, 3)) 14 | expect_equal(out$ncol, list(2, 2, 2)) 15 | }) 16 | 17 | test_that("unnamed results bound together by row", { 18 | mf <- memdb_frame( 19 | g = c(1, 1, 2, 2), 20 | x = c(3, 9, 4, 9) 21 | ) %>% group_by(g) 22 | 23 | first <- mf %>% do(head(., 1)) %>% ungroup() 24 | compare_tbl(first, tibble(g = c(1, 2), x = c(3, 4))) 25 | }) 26 | 27 | test_that("unnamed results must be data frames", { 28 | mf <- memdb_frame( 29 | g = c(1, 1, 2, 2), 30 | x = c(3, 9, 4, 9) 31 | ) %>% group_by(g) 32 | 33 | expect_snapshot(error = TRUE, mf %>% do(nrow(.))) 34 | }) 35 | 36 | test_that("Results respect select", { 37 | mf <- memdb_frame( 38 | g = c(1, 1, 2, 2), 39 | x = c(3, 9, 4, 9), 40 | y = 1:4, 41 | z = 4:1 42 | ) %>% group_by(g) 43 | 44 | expect_message(out <- mf %>% select(x) %>% do(ncol = ncol(.))) 45 | expect_equal(out$g, c(1, 2)) 46 | expect_equal(out$ncol, list(2L, 2L)) 47 | }) 48 | 49 | test_that("results independent of chunk_size", { 50 | mf <- memdb_frame( 51 | g = rep(1:3, 1:3), 52 | x = 1:6 53 | ) %>% group_by(g) 54 | 55 | nrows <- function(group, n) { 56 | unlist(do(group, nrow = nrow(.), .chunk_size = n)$nrow) 57 | } 58 | 59 | expect_equal(nrows(mf, 1), c(1, 2, 3)) 60 | expect_equal(nrows(mf, 2), c(1, 2, 3)) 61 | expect_equal(nrows(mf, 10), c(1, 2, 3)) 62 | }) 63 | 64 | test_that("named argument become list columns", { 65 | mf <- memdb_frame( 66 | g = rep(1:3, 1:3), 67 | x = 1:6 68 | ) %>% group_by(g) 69 | 70 | # mix named and unnamed 71 | expect_snapshot(error = TRUE, mf %>% do(nrow = nrow(.), ncol(.))) 72 | 73 | # multiple unnamed 74 | expect_snapshot(error = TRUE, mf %>% do(nrow(.), ncol(.))) 75 | 76 | # old syntax 77 | expect_snapshot(error = TRUE, mf %>% do(.f = nrow)) 78 | }) 79 | -------------------------------------------------------------------------------- /tests/testthat/test-verb-head.R: -------------------------------------------------------------------------------- 1 | test_that("head limits rows", { 2 | db <- head(memdb_frame(x = 1:100), 10) 3 | 4 | expect_equal(sql_build(db)$limit, 10) 5 | expect_equal(nrow(collect(db)), 10) 6 | }) 7 | 8 | test_that("two heads are equivalent to one", { 9 | out <- lazy_frame(x = 1:10) %>% head(3) %>% head(5) 10 | expect_equal(out$lazy_query$limit, 3) 11 | }) 12 | 13 | test_that("non-integer automatically truncated", { 14 | out <- lazy_frame(x = 1:10) %>% head(3.5) 15 | expect_equal(out$lazy_query$limit, 3) 16 | }) 17 | 18 | test_that("can get 0 rows", { 19 | db <- memdb_frame(x = 1) 20 | out <- collect(head(db, 0)) 21 | expect_equal(out, tibble(x = double())) 22 | }) 23 | 24 | test_that("n must be valid", { 25 | db <- memdb_frame(x = 1) 26 | 27 | expect_error(head(db, "x"), "non-negative integer") 28 | expect_error(head(db, 1:2), "non-negative integer") 29 | expect_error(head(db, -1), "non-negative integer") 30 | expect_error(head(db, Inf), NA) 31 | }) 32 | 33 | test_that("tail not supported", { 34 | lf <- lazy_frame(x = 1) 35 | expect_error(tail(lf), "not supported") 36 | }) 37 | -------------------------------------------------------------------------------- /tests/testthat/test-verb-pull.R: -------------------------------------------------------------------------------- 1 | test_that("default extracts last var from data frame", { 2 | df <- memdb_frame(x = 1:3, z = 4:6) 3 | expect_equal(pull(df), 4:6) 4 | }) 5 | 6 | test_that("can extract by name, or positive/negative position", { 7 | x <- 1:3 8 | df <- memdb_frame(x = x, y = 4:6) 9 | 10 | expect_equal(pull(df, x), x) 11 | expect_equal(pull(df, 1L), x) 12 | expect_equal(pull(df, 1), x) 13 | expect_equal(pull(df, -2), x) 14 | expect_equal(pull(df, -2L), x) 15 | }) 16 | 17 | test_that("extracts correct column from grouped tbl", { 18 | mf <- memdb_frame(id = "a", value = 42) 19 | gf <- mf %>% group_by(id) 20 | 21 | expect_equal(pull(mf, value), 42) 22 | }) 23 | 24 | test_that("doesn't unnecessarily select", { 25 | mf <- memdb_frame(x = c(3, 1, 2)) 26 | # no warning about select after arrange 27 | expect_warning(out <- mf %>% arrange(x) %>% pull(), NA) 28 | expect_equal(out, 1:3) 29 | }) 30 | 31 | test_that("can extract named vectors", { 32 | x <- 1:3 33 | y <- letters[x] 34 | df <- memdb_frame(x = x, y = y) 35 | xn <- set_names(x, y) 36 | 37 | expect_equal(pull(df, x), x) 38 | expect_equal(pull(df, x, y), xn) 39 | expect_equal(pull(df, 1, 2), xn) 40 | expect_equal(names(pull(df, x, y)), y) 41 | }) 42 | 43 | 44 | test_that("ungroup() produces nice error messages", { 45 | expect_snapshot(error = TRUE, { 46 | memdb_frame(x = 1) %>% pull(non_existent) 47 | memdb_frame(x = 1) %>% pull("non_existent") 48 | memdb_frame(x = 1) %>% pull(1000) 49 | 50 | memdb_frame(x = 1) %>% pull(x, "name_non_existent") 51 | }) 52 | }) 53 | 54 | -------------------------------------------------------------------------------- /tests/testthat/test-verb-window.R: -------------------------------------------------------------------------------- 1 | test_that("window_order errors for data frame", { 2 | expect_snapshot({ 3 | (expect_error(window_order(data.frame(x = 1)))) 4 | (expect_error(window_order("a"))) 5 | }) 6 | }) 7 | 8 | test_that("window_order only accepts variables", { 9 | lf <- lazy_frame(x = 1, y = 1) 10 | expect_equal(window_order(lf, x, y) %>% op_sort(), unname(exprs(x, y))) 11 | expect_equal(window_order(lf, x, desc(y)) %>% op_sort(), unname(exprs(x, desc(y)))) 12 | 13 | expect_snapshot({ 14 | (expect_error(window_order(lf, x + y))) 15 | }) 16 | }) 17 | 18 | test_that("window order works afer renaming variable", { 19 | expect_snapshot({ 20 | lazy_frame(x = 1, y = 1) %>% 21 | window_order(y) %>% 22 | rename(y2 = y) %>% 23 | mutate(x_cum = cumsum(x)) 24 | 25 | lazy_frame(x = 1, y = 1) %>% 26 | rename(y2 = y) %>% 27 | window_order(y2) %>% 28 | mutate(x_cum = cumsum(x)) 29 | }) 30 | }) 31 | 32 | test_that("window_frame errors for data frame", { 33 | expect_snapshot({ 34 | (expect_error(window_frame(data.frame(x = 1)))) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | figure 4 | *.md 5 | rsconnect 6 | -------------------------------------------------------------------------------- /vignettes/setup/_mssql.Rmd: -------------------------------------------------------------------------------- 1 | # MySQL 2 | 3 | ## Install drivers 4 | 5 | ``` 6 | brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release 7 | brew update 8 | brew install msodbcsql17 mssql-tools 9 | ``` 10 | 11 | Check available: 12 | 13 | ```{r} 14 | odbc::odbcListDrivers() 15 | edit_file("/usr/local/etc/odbcinst.ini") 16 | Sys.setenv("GITHUB_MSSQL" = "true") 17 | ``` 18 | 19 | ## Start 20 | 21 | ``` 22 | docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password12' -t -i -p 1433:1433 microsoft/mssql-server-linux 23 | 24 | sqlcmd -U SA -P 'Password12' -Q 'CREATE DATABASE test;' 25 | ``` 26 | 27 | ## Connect 28 | 29 | ```{r, eval = FALSE} 30 | con <- DBI::dbConnect(odbc::odbc(), 31 | driver = "ODBC Driver 17 for SQL Server", 32 | database = "test", 33 | uid = "SA", 34 | pwd = "Password12", 35 | server = "localhost", 36 | port = 1433 37 | ) 38 | ``` 39 | -------------------------------------------------------------------------------- /vignettes/setup/_mysql.Rmd: -------------------------------------------------------------------------------- 1 | # MariaDB 2 | 3 | ## Install 4 | 5 | ``` 6 | brew install mariadb 7 | mysql_install_db --verbose --user=hadley --basedir=/usr/local \ 8 | --datadir=/User/hadley/db/mariadb --tmpdir=/tmp 9 | 10 | mysqld --datadir='/Users/hadley/db/mysql' 11 | 12 | mysql -u root -e "CREATE DATABASE lahman;" 13 | mysql -u root -e "CREATE DATABASE nycflights13;" 14 | mysql -u root -e "CREATE DATABASE test;" 15 | ``` 16 | 17 | ## Start 18 | 19 | ``` 20 | mysqld --datadir='/Users/hadley/db/mysql' 21 | ``` 22 | 23 | ## Connect 24 | 25 | ```{r, eval = FALSE} 26 | install.packages("RMariaDB") 27 | 28 | con <- dbConnect(RMariaDB::MariaDB(), dbname = "lahman", username = "root", password = "") 29 | dbListTables(con) 30 | ``` 31 | 32 | # Shut down 33 | 34 | ``` 35 | mysqladmin shutdown -u root -p 36 | ``` 37 | -------------------------------------------------------------------------------- /vignettes/setup/_postgres.Rmd: -------------------------------------------------------------------------------- 1 | # PostgreSQL 2 | 3 | ## Install 4 | 5 | First install PostgreSQL, create a data directory, and create a default database. 6 | 7 | ``` 8 | brew install postgresql 9 | export PGDATA=~/db/postgres # set this globally somewhere 10 | initdb 11 | createdb test 12 | 13 | psql -c "CREATE USER postgres WITH PASSWORD 'password';" 14 | psql -c "ALTER USER postgres WITH SUPERUSER;" 15 | ``` 16 | 17 | ## Start 18 | 19 | ``` 20 | pg_ctl start 21 | ``` 22 | 23 | ## Connect 24 | 25 | ```{r, eval = FALSE} 26 | library(DBI) 27 | con <- dbConnect(RPostgres::Postgres(), dbname = "hadley") 28 | dbListTables(con) 29 | 30 | con <- dbConnect( 31 | RPostgres::Postgres(), 32 | dbname = "test", 33 | user = "postgres", 34 | password = "passowrd" 35 | ) 36 | ``` 37 | -------------------------------------------------------------------------------- /vignettes/setup/_sap-hana.Rmd: -------------------------------------------------------------------------------- 1 | # SAP HANA 2 | 3 | ## Sign up for free cloud trial 4 | 5 | * 6 | * Go to 7 | * Click trial, then "dev" space. 8 | * Then follow 9 | * Allow access from all IP addresses. 10 | * Need to restart service every day; it's automatically stopped each night. 11 | * Need to create `test` database using database explorer 12 | 13 | ## Install drivers 14 | 15 | * Download SAP HANA installer from 16 | * Uncheck virtual machine; check "clients (mac)" 17 | * Untar download 18 | * Untar `hdb_client_mac.tgz` 19 | * `./hdb_inst` 20 | 21 | Configure odbc.init: `edit_file("/usr/local/etc/odbcinst.ini")` 22 | 23 | ``` 24 | [SAP HANA] 25 | Description=SAP HANA 26 | Driver=/Applications/sap/hdbclient/libodbcHDB.dylib 27 | ``` 28 | 29 | Check: 30 | 31 | ```{r} 32 | odbc::odbcListDrivers() 33 | ``` 34 | 35 | ## Connect 36 | 37 | ```{r, eval = FALSE} 38 | con <- DBI::dbConnect(odbc::odbc(), 39 | driver = "SAP HANA", 40 | uid = "DBADMIN", 41 | pwd = "Password12", 42 | servernode = "a9441502-7166-4a5a-b5d8-23abe3b5009c.hana.trial-us10.hanacloud.ondemand.com:443", 43 | encrypt="true", 44 | sslValidateCertificate = "false" 45 | ) 46 | class(con) 47 | #> [1] "HDB" 48 | ``` 49 | -------------------------------------------------------------------------------- /vignettes/windows.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/vignettes/windows.graffle -------------------------------------------------------------------------------- /vignettes/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidyverse/dbplyr/99a70f554dba41945f6d36dd8a01b6151537076f/vignettes/windows.png --------------------------------------------------------------------------------