From a82fc0da93a3a392e92295184468251d15a14343 Mon Sep 17 00:00:00 2001 From: Nicolas Bennett <3158446+nbenn@users.noreply.github.com> Date: Wed, 29 May 2024 14:28:51 +0200 Subject: [PATCH] Initial commit --- .Rbuildignore | 9 + .aviator/config.yml | 43 +++ .github/.gitignore | 1 + .github/CONTRIBUTING.md | 37 ++ .github/ISSUE_TEMPLATE.md | 13 + .github/security.md | 4 + .github/workflows/R-CMD-check-dev.yaml | 150 ++++++++ .github/workflows/R-CMD-check.yaml | 348 ++++++++++++++++++ .github/workflows/check/action.yml | 40 ++ .github/workflows/commit/action.yml | 29 ++ .../workflows/dep-matrix-suggests/action.yml | 56 +++ .github/workflows/dep-matrix/action.yml | 134 +++++++ .github/workflows/fledge.yaml | 58 +++ .github/workflows/get-extra/action.yml | 16 + .github/workflows/git-identity/action.yml | 11 + .github/workflows/install/action.yml | 117 ++++++ .github/workflows/lock.yaml | 19 + .github/workflows/pkgdown-build/action.yml | 9 + .github/workflows/pkgdown-deploy/action.yml | 12 + .github/workflows/pkgdown.yaml | 54 +++ .github/workflows/pr-commands.yaml | 103 ++++++ .github/workflows/rate-limit/action.yml | 13 + .github/workflows/revdep.yaml | 213 +++++++++++ .github/workflows/roxygenize/action.yml | 9 + .github/workflows/style/action.yml | 71 ++++ .github/workflows/update-snapshots/action.yml | 82 +++++ .gitignore | 2 + CODE_OF_CONDUCT.md | 25 ++ DESCRIPTION | 78 ++++ LICENSE.md | 43 +++ NAMESPACE | 62 ++++ NEWS.md | 104 ++++++ R/Connection.R | 47 +++ R/Driver.R | 38 ++ R/RKazam-package.R | 8 + R/Result.R | 21 ++ R/ResultArrow.R | 21 ++ ...endTable_Connection_character_data.frame.R | 22 ++ R/dbBegin_Connection.R | 9 + R/dbBind_Result.R | 9 + R/dbClearResult_Result.R | 9 + R/dbClearResult_ResultArrow.R | 10 + R/dbColumnInfo_Result.R | 9 + R/dbCommit_Connection.R | 9 + R/dbConnect_Driver.R | 10 + R/dbDataType_Connection.R | 12 + R/dbDataType_Driver.R | 13 + R/dbDataType_Driver_list.R | 10 + R/dbDisconnect_Connection.R | 14 + R/dbExistsTable_Connection_character.R | 19 + R/dbFetchArrow_ResultArrow.R | 10 + R/dbFetch_Result.R | 18 + R/dbGetInfo_Connection.R | 9 + R/dbGetInfo_Driver.R | 9 + R/dbGetInfo_Result.R | 10 + R/dbGetRowCount_Result.R | 9 + R/dbGetRowsAffected_Result.R | 9 + R/dbGetStatement_Result.R | 9 + R/dbHasCompleted_Result.R | 9 + R/dbIsValid_Connection.R | 10 + R/dbIsValid_Driver.R | 9 + R/dbIsValid_Result.R | 9 + R/dbListFields_Connection_character.R | 9 + R/dbListTables_Connection.R | 9 + R/dbQuoteIdentifier_Connection_character.R | 10 + R/dbQuoteString_Connection_character.R | 10 + R/dbRemoveTable_Connection_character.R | 25 ++ R/dbRollback_Connection.R | 9 + R/dbSendQueryArrow_Connection.R | 18 + R/dbSendQuery_Connection_character.R | 16 + R/dbSendStatement_Connection_character.R | 16 + ...iteTable_Connection_character_data.frame.R | 82 +++++ R/show_Connection.R | 10 + R/show_Driver.R | 10 + R/show_Result.R | 10 + README.md | 23 ++ RKazam.Rproj | 22 ++ _pkgdown.yml | 32 ++ codecov.yml | 14 + man/DBI.Rd | 261 +++++++++++++ man/Kazam.Rd | 17 + man/RKazam-package.Rd | 28 ++ man/reexports.Rd | 27 ++ tests/testthat.R | 3 + tests/testthat/helper-DBItest.R | 22 ++ tests/testthat/test-DBItest.R | 3 + 86 files changed, 3061 insertions(+) create mode 100644 .Rbuildignore create mode 100644 .aviator/config.yml create mode 100644 .github/.gitignore create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/security.md create mode 100644 .github/workflows/R-CMD-check-dev.yaml create mode 100644 .github/workflows/R-CMD-check.yaml create mode 100644 .github/workflows/check/action.yml create mode 100644 .github/workflows/commit/action.yml create mode 100644 .github/workflows/dep-matrix-suggests/action.yml create mode 100644 .github/workflows/dep-matrix/action.yml create mode 100644 .github/workflows/fledge.yaml create mode 100644 .github/workflows/get-extra/action.yml create mode 100644 .github/workflows/git-identity/action.yml create mode 100644 .github/workflows/install/action.yml create mode 100644 .github/workflows/lock.yaml create mode 100644 .github/workflows/pkgdown-build/action.yml create mode 100644 .github/workflows/pkgdown-deploy/action.yml create mode 100644 .github/workflows/pkgdown.yaml create mode 100644 .github/workflows/pr-commands.yaml create mode 100644 .github/workflows/rate-limit/action.yml create mode 100644 .github/workflows/revdep.yaml create mode 100644 .github/workflows/roxygenize/action.yml create mode 100644 .github/workflows/style/action.yml create mode 100644 .github/workflows/update-snapshots/action.yml create mode 100644 .gitignore create mode 100644 CODE_OF_CONDUCT.md create mode 100644 DESCRIPTION create mode 100644 LICENSE.md create mode 100644 NAMESPACE create mode 100644 NEWS.md create mode 100644 R/Connection.R create mode 100644 R/Driver.R create mode 100644 R/RKazam-package.R create mode 100644 R/Result.R create mode 100644 R/ResultArrow.R create mode 100644 R/dbAppendTable_Connection_character_data.frame.R create mode 100644 R/dbBegin_Connection.R create mode 100644 R/dbBind_Result.R create mode 100644 R/dbClearResult_Result.R create mode 100644 R/dbClearResult_ResultArrow.R create mode 100644 R/dbColumnInfo_Result.R create mode 100644 R/dbCommit_Connection.R create mode 100644 R/dbConnect_Driver.R create mode 100644 R/dbDataType_Connection.R create mode 100644 R/dbDataType_Driver.R create mode 100644 R/dbDataType_Driver_list.R create mode 100644 R/dbDisconnect_Connection.R create mode 100644 R/dbExistsTable_Connection_character.R create mode 100644 R/dbFetchArrow_ResultArrow.R create mode 100644 R/dbFetch_Result.R create mode 100644 R/dbGetInfo_Connection.R create mode 100644 R/dbGetInfo_Driver.R create mode 100644 R/dbGetInfo_Result.R create mode 100644 R/dbGetRowCount_Result.R create mode 100644 R/dbGetRowsAffected_Result.R create mode 100644 R/dbGetStatement_Result.R create mode 100644 R/dbHasCompleted_Result.R create mode 100644 R/dbIsValid_Connection.R create mode 100644 R/dbIsValid_Driver.R create mode 100644 R/dbIsValid_Result.R create mode 100644 R/dbListFields_Connection_character.R create mode 100644 R/dbListTables_Connection.R create mode 100644 R/dbQuoteIdentifier_Connection_character.R create mode 100644 R/dbQuoteString_Connection_character.R create mode 100644 R/dbRemoveTable_Connection_character.R create mode 100644 R/dbRollback_Connection.R create mode 100644 R/dbSendQueryArrow_Connection.R create mode 100644 R/dbSendQuery_Connection_character.R create mode 100644 R/dbSendStatement_Connection_character.R create mode 100644 R/dbWriteTable_Connection_character_data.frame.R create mode 100644 R/show_Connection.R create mode 100644 R/show_Driver.R create mode 100644 R/show_Result.R create mode 100644 README.md create mode 100644 RKazam.Rproj create mode 100644 _pkgdown.yml create mode 100644 codecov.yml create mode 100644 man/DBI.Rd create mode 100644 man/Kazam.Rd create mode 100644 man/RKazam-package.Rd create mode 100644 man/reexports.Rd create mode 100644 tests/testthat.R create mode 100644 tests/testthat/helper-DBItest.R create mode 100644 tests/testthat/test-DBItest.R diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..cab0e96 --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,9 @@ +^.*\.Rproj$ +^\.Rproj\.user$ +^_pkgdown\.yml$ +^docs$ +^\.github$ +^codecov\.yml$ +^LICENSE\.md$ +^CODE_OF_CONDUCT\.md$ +^\.aviator/config\.yml$ diff --git a/.aviator/config.yml b/.aviator/config.yml new file mode 100644 index 0000000..968c74b --- /dev/null +++ b/.aviator/config.yml @@ -0,0 +1,43 @@ +merge_rules: + labels: + trigger: mergequeue + skip_line: mergequeue-priority + merge_failed: blocked + skip_delete_branch: '' + update_latest: true + delete_branch: false + use_rebase: true + publish_status_check: ready + status_comment: + publish: always + open_message: '' + queued_message: '' + blocked_message: '' + enable_comments: true + ci_timeout_mins: 0 + require_all_checks_pass: true + require_skip_line_reason: false + preconditions: + validations: [] + number_of_approvals: 0 + required_checks: [] + use_github_mergeability: true + conversation_resolution_required: false + merge_mode: + type: default + auto_update: + enabled: true + label: 'mergequeue' + max_runs_for_update: 0 + merge_commit: + use_title_and_body: false + merge_strategy: + name: merge + override_labels: + squash: '' + merge: '' + rebase: '' + base_branches: + - main +scenarios: [] +version: 1.1.0 diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..6917e2d --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +/pkg.lock diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..1782210 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,37 @@ +# Contributing to RKazam + +This outlines how to propose a change to RKazam. + +### Fixing typos + +Small typos or grammatical errors in documentation may be edited directly using +the GitHub web interface, so long as the changes are made in the _source_ file. + +* YES: you edit a roxygen comment in a `.R` file below `R/`. +* NO: you edit an `.Rd` file below `man/`. + +### Prerequisites + +Before you make a substantial pull request, you should always file an issue and +make sure someone from the team agrees that it’s a problem. If you’ve found a +bug, create an associated issue and illustrate the bug with a minimal +[reprex](https://www.tidyverse.org/help/#reprex). + +### Pull request process + +* We recommend that you create a Git branch for each pull request (PR). +* Look at the Travis and AppVeyor build status before and after making changes. +The `README` should contain badges for any continuous integration services used +by the package. +* We use [roxygen2](https://cran.r-project.org/package=roxygen2), with +[Markdown syntax](https://cran.r-project.org/web/packages/roxygen2/vignettes/markdown.html), +for documentation. +* We use [testthat](https://cran.r-project.org/package=testthat). Contributions +with test cases included are easier to accept. +* Please do not update `NEWS.md`. + +### Code of Conduct + +Please note that the RKazam project is released with a +[Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to this +project you agree to abide by its terms. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..e7b1637 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,13 @@ +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 . + +Please include a minimal reproducible example (AKA a reprex). If you've never heard of a [reprex](https://reprex.tidyverse.org/) before, start by reading . + +IMPORTANT: If your code requires accessing a specific database (with e.g. odbc, RSQLite, RJDBC), the issue you are experiencing is likely not a problem with the DBI package. Please file an issue with the appropriate DBI backend instead. + +--- + +Brief description of the problem + +```r +# insert reprex here +``` diff --git a/.github/security.md b/.github/security.md new file mode 100644 index 0000000..bd27244 --- /dev/null +++ b/.github/security.md @@ -0,0 +1,4 @@ +# Process for reporting security vulnerabilities + +For reporting a security vulnerability, please e-mail the package maintainer at krlmlr+r@mailbox.org for further instructions. +Do not include confidential information in the e-mail. diff --git a/.github/workflows/R-CMD-check-dev.yaml b/.github/workflows/R-CMD-check-dev.yaml new file mode 100644 index 0000000..23c4a6b --- /dev/null +++ b/.github/workflows/R-CMD-check-dev.yaml @@ -0,0 +1,150 @@ +# This workflow calls the GitHub API very frequently. +# Can't be run as part of commits +on: + schedule: + - cron: "5 0 * * *" # 05:00 UTC every day only run on main branch + push: + branches: + - "cran-*" + tags: + - "v*" + +name: rcc dev + +jobs: + matrix: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + + name: Collect deps + + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: r-lib/actions/setup-r@v2 + with: + install-r: false + + - id: set-matrix + uses: ./.github/workflows/dep-matrix + + check-matrix: + runs-on: ubuntu-22.04 + needs: matrix + + name: Check deps + + steps: + - name: Install json2yaml + run: | + sudo npm install -g json2yaml + + - name: Check matrix definition + run: | + matrix='${{ needs.matrix.outputs.matrix }}' + echo $matrix + echo $matrix | jq . + echo $matrix | json2yaml + + R-CMD-check-base: + runs-on: ubuntu-22.04 + + name: base + + # Begin custom: services + # End custom: services + + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/workflows/custom/before-install + if: hashFiles('.github/workflows/custom/before-install/action.yml') != '' + + - uses: ./.github/workflows/install + with: + install-r: false + cache-version: rcc-dev-base-1 + needs: check + extra-packages: "any::rcmdcheck any::remotes ." + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Session info + run: | + options(width = 100) + if (!requireNamespace("sessioninfo", quietly = TRUE)) install.packages("sessioninfo") + pkgs <- installed.packages()[, "Package"] + sessioninfo::session_info(pkgs, include_base = TRUE) + shell: Rscript {0} + + - uses: ./.github/workflows/custom/after-install + if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' + + - uses: ./.github/workflows/update-snapshots + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + + - uses: ./.github/workflows/check + with: + results: ${{ matrix.package }} + + R-CMD-check-dev: + needs: + - matrix + - R-CMD-check-base + + runs-on: ubuntu-22.04 + + name: ${{ matrix.package }} + + # Begin custom: services + # End custom: services + + strategy: + fail-fast: false + matrix: ${{fromJson(needs.matrix.outputs.matrix)}} + + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/workflows/custom/before-install + if: hashFiles('.github/workflows/custom/before-install/action.yml') != '' + + - uses: ./.github/workflows/install + with: + install-r: false + cache-version: rcc-dev-${{ matrix.package }}-1 + needs: check + extra-packages: "any::rcmdcheck any::remotes ." + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install dev version of ${{ matrix.package }} + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + run: | + remotes::install_dev("${{ matrix.package }}", "https://cloud.r-project.org", upgrade = "always") + shell: Rscript {0} + + - name: Session info + run: | + options(width = 100) + if (!requireNamespace("sessioninfo", quietly = TRUE)) install.packages("sessioninfo") + pkgs <- installed.packages()[, "Package"] + sessioninfo::session_info(pkgs, include_base = TRUE) + shell: Rscript {0} + + - uses: ./.github/workflows/custom/after-install + if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' + + - uses: ./.github/workflows/update-snapshots + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + + - uses: ./.github/workflows/check + with: + results: ${{ matrix.package }} diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml new file mode 100644 index 0000000..921c120 --- /dev/null +++ b/.github/workflows/R-CMD-check.yaml @@ -0,0 +1,348 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +# +# NOTE: This workflow is overkill for most R packages and +# check-standard.yaml is likely a better choice. +# usethis::use_github_action("check-standard") will install it. +on: + push: + branches: + - main + - master + pull_request: + branches: + - main + - master + schedule: + - cron: "10 0 * * *" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.sha }}-${{ github.base_ref || '' }} + cancel-in-progress: true + +name: rcc + +jobs: + rcc-smoke: + runs-on: ubuntu-latest + outputs: + sha: ${{ steps.commit.outputs.sha }} + + name: "Smoke test: stock R" + + # Begin custom: services + # End custom: services + + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: ./.github/workflows/git-identity + + - uses: ./.github/workflows/custom/before-install + if: hashFiles('.github/workflows/custom/before-install/action.yml') != '' + + - uses: ./.github/workflows/install + with: + token: ${{ secrets.GITHUB_TOKEN }} + install-r: false + cache-version: rcc-smoke-2 + needs: check + extra-packages: any::rcmdcheck any::roxygen2 r-lib/styler + + - uses: ./.github/workflows/custom/after-install + if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' + + - uses: ./.github/workflows/update-snapshots + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + + - uses: ./.github/workflows/style + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + + - uses: ./.github/workflows/roxygenize + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + + - id: commit + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + uses: ./.github/workflows/commit + + - uses: ./.github/workflows/check + with: + results: ${{ runner.os }}-smoke-test + + # Runs in a separate workflow, because it's using dev pkgdown + # which might bring in other dev dependencies + pkgdown: + needs: rcc-smoke + + runs-on: ubuntu-latest + + name: "pkgdown" + + # Begin custom: services + # End custom: services + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.rcc-smoke.outputs.sha }} + + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: ./.github/workflows/git-identity + if: github.event_name == 'push' + + - uses: ./.github/workflows/custom/before-install + if: hashFiles('.github/workflows/custom/before-install/action.yml') != '' + + - uses: ./.github/workflows/install + with: + token: ${{ secrets.GITHUB_TOKEN }} + install-r: false + cache-version: pkgdown-1 + needs: website + extra-packages: r-lib/pkgdown local::. + + - uses: ./.github/workflows/custom/after-install + if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' + + - uses: ./.github/workflows/pkgdown-build + if: github.event_name != 'push' + + - uses: ./.github/workflows/pkgdown-deploy + if: github.event_name == 'push' + + # Windows checks can be run in parallel and independently + # when they alone take as long as the smoke and full tests combined. + # To achieve this, remove the "needs:" element below. + rcc-windows: + # Begin custom: early run + needs: rcc-smoke + # End custom: early run + + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) ${{ matrix.config.desc }} + + # Begin custom: services + # End custom: services + + strategy: + fail-fast: false + matrix: + config: + - {os: windows-latest, r: 'release'} + # Use 3.6 to trigger usage of RTools35 + - {os: windows-latest, r: '3.6'} + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.rcc-smoke.outputs.sha }} + + - uses: ./.github/workflows/custom/before-install + if: hashFiles('.github/workflows/custom/before-install/action.yml') != '' + + - uses: ./.github/workflows/install + with: + r-version: ${{ matrix.config.r }} + cache-version: rcc-windows-1 + token: ${{ secrets.GITHUB_TOKEN }} + needs: check + + - uses: ./.github/workflows/custom/after-install + if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' + + - uses: ./.github/workflows/update-snapshots + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + + - uses: ./.github/workflows/check + with: + results: ${{ runner.os }}-r${{ matrix.config.r }} + + rcc-full: + needs: rcc-smoke + + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) ${{ matrix.config.desc }} + + # Begin custom: services + # End custom: services + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + + - {os: ubuntu-20.04, r: 'release'} + + # Use older ubuntu to maximise backward compatibility + - {os: ubuntu-22.04, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-22.04, r: 'release', covr: true, desc: 'with covr'} + - {os: ubuntu-22.04, r: 'oldrel-1'} + + # Begin custom: R 3.6 + - {os: ubuntu-22.04, r: 'oldrel-2'} + # End custom: R 3.6 + + # Begin custom: R 3.5 + - {os: ubuntu-22.04, r: 'oldrel-3'} + # End custom: R 3.5 + + # Begin custom: R 3.4 + - {os: ubuntu-22.04, r: 'oldrel-4'} + # End custom: R 3.4 + + # Begin custom: matrix elements + # End custom: matrix elements + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.rcc-smoke.outputs.sha }} + + - uses: ./.github/workflows/custom/before-install + if: hashFiles('.github/workflows/custom/before-install/action.yml') != '' + + - uses: ./.github/workflows/install + with: + r-version: ${{ matrix.config.r }} + cache-version: rcc-full-1 + token: ${{ secrets.GITHUB_TOKEN }} + needs: check + + - uses: ./.github/workflows/custom/after-install + if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' + + - uses: ./.github/workflows/update-snapshots + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + + - uses: ./.github/workflows/check + with: + results: ${{ runner.os }}-r${{ matrix.config.r }} + + suggests-matrix: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + + name: Collect suggests deps + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: r-lib/actions/setup-r@v2 + with: + install-r: false + use-public-rspm: true + + - id: set-matrix + uses: ./.github/workflows/dep-matrix-suggests + + check-matrix: + runs-on: ubuntu-22.04 + needs: suggests-matrix + + name: Check deps + + if: ${{ needs.matrix.outputs.matrix != '' }} + + steps: + - name: Install json2yaml + run: | + sudo npm install -g json2yaml + + - name: Check matrix definition + run: | + matrix='${{ needs.matrix.outputs.matrix }}' + echo $matrix + echo $matrix | jq . + echo $matrix | json2yaml + + rcc-suggests: + needs: + - suggests-matrix + - rcc-smoke + + runs-on: ubuntu-22.04 + + name: Without ${{ matrix.package }} + + if: ${{ needs.suggests-matrix.outputs.matrix != '' }} + + # Begin custom: services + # End custom: services + + strategy: + fail-fast: false + matrix: ${{fromJson(needs.suggests-matrix.outputs.matrix)}} + + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/workflows/custom/before-install + if: hashFiles('.github/workflows/custom/before-install/action.yml') != '' + + - uses: ./.github/workflows/install + with: + install-r: false + cache-version: rcc-dev-${{ matrix.package }}-1 + needs: check + extra-packages: "any::rcmdcheck any::remotes ." + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Remove ${{ matrix.package }} and all strong dependencies + run: | + pkg <- "${{ matrix.package }}" + pkgs <- tools::package_dependencies(pkg, reverse = TRUE)[[1]] + installed <- rownames(utils::installed.packages()) + to_remove <- c(pkg, intersect(pkgs, installed)) + print(to_remove) + remove.packages(to_remove) + shell: Rscript {0} + + - name: Session info + run: | + options(width = 100) + if (!requireNamespace("sessioninfo", quietly = TRUE)) install.packages("sessioninfo") + pkgs <- installed.packages()[, "Package"] + sessioninfo::session_info(pkgs, include_base = TRUE) + shell: Rscript {0} + + - uses: ./.github/workflows/custom/after-install + if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' + + - name: Define _R_CHECK_FORCE_SUGGESTS_ + run: | + cat('_R_CHECK_FORCE_SUGGESTS_=false\n', file = Sys.getenv("GITHUB_ENV"), append = TRUE) + shell: Rscript {0} + + - name: Must allow NOTEs, even with _R_CHECK_FORCE_SUGGESTS_ + run: | + if (Sys.getenv("RCMDCHECK_ERROR_ON") %in% c("", "note")) { + cat('RCMDCHECK_ERROR_ON="warning"\n', file = Sys.getenv("GITHUB_ENV"), append = TRUE) + } + shell: Rscript {0} + + - name: Check env vars + run: | + print(Sys.getenv('_R_CHECK_FORCE_SUGGESTS_')) + print(Sys.getenv('RCMDCHECK_ERROR_ON')) + shell: Rscript {0} + + - uses: ./.github/workflows/check + with: + results: ${{ matrix.package }} diff --git a/.github/workflows/check/action.yml b/.github/workflows/check/action.yml new file mode 100644 index 0000000..afb3819 --- /dev/null +++ b/.github/workflows/check/action.yml @@ -0,0 +1,40 @@ +name: "Actions to check an R package" +inputs: + results: + description: Slug for check results + required: true + +runs: + using: "composite" + steps: + - uses: r-lib/actions/check-r-package@v2 + with: + # Fails on R 3.6 on Windows, remove when this job is removed? + args: 'c("--no-manual", "--as-cran", "--no-multiarch")' + error-on: ${{ env.RCMDCHECK_ERROR_ON || '"note"' }} + + - name: Run coverage check + if: ${{ matrix.config.covr }} + run: | + if (dir.exists("tests/testthat")) { + covr::codecov() + } else { + message("No tests found, coverage not tested.") + } + shell: Rscript {0} + + - name: Show test output + if: always() + run: | + ## -- Show test output -- + echo "::group::Test output" + find check -name '*.Rout*' -exec head -n 1000000 '{}' \; || true + echo "::endgroup::" + shell: bash + + - name: Upload check results + if: failure() + uses: actions/upload-artifact@main + with: + name: ${{ inputs.results }}-results + path: check diff --git a/.github/workflows/commit/action.yml b/.github/workflows/commit/action.yml new file mode 100644 index 0000000..89be422 --- /dev/null +++ b/.github/workflows/commit/action.yml @@ -0,0 +1,29 @@ +name: "Action to commit changes to the repository" +outputs: + sha: + description: "SHA of generated commit" + value: ${{ steps.commit.outputs.sha }} + +runs: + using: "composite" + steps: + - name: Commit if changed + id: commit + run: | + set -x + if [ -n "$(git status --porcelain)" ]; then + echo "Changed" + git fetch + if [ -n "${GITHUB_HEAD_REF}" ]; then + git add . + git stash save + git switch ${GITHUB_HEAD_REF} + git merge origin/${GITHUB_BASE_REF} --no-edit + git stash pop + fi + git add . + git commit -m "Auto-update from GitHub Actions"$'\n'$'\n'"Run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + git push -u origin HEAD + echo sha=$(git rev-parse HEAD) >> $GITHUB_OUTPUT + fi + shell: bash diff --git a/.github/workflows/dep-matrix-suggests/action.yml b/.github/workflows/dep-matrix-suggests/action.yml new file mode 100644 index 0000000..deafab9 --- /dev/null +++ b/.github/workflows/dep-matrix-suggests/action.yml @@ -0,0 +1,56 @@ +name: "Actions to compute a matrix with all suggested packages" +outputs: + matrix: + description: "Generated matrix" + value: ${{ steps.set-matrix.outputs.matrix }} + +runs: + using: "composite" + steps: + - id: set-matrix + run: | + get_deps <- function() { + # Determine package dependencies + if (!requireNamespace("desc", quietly = TRUE)) { + install.packages("desc") + } + + deps_df <- desc::desc_get_deps() + deps_df_optional <- deps_df$package[deps_df$type %in% c("Suggests", "Enhances")] + deps_df_hard <- deps_df$package[deps_df$type %in% c("Depends", "Imports", "LinkingTo")] + + packages <- sort(deps_df_optional) + packages <- intersect(packages, rownames(available.packages())) + + # Too big to fail, or can't be avoided: + off_limits <- c("testthat", "rmarkdown", "rcmdcheck", deps_df_hard) + off_limits_dep <- unlist(tools::package_dependencies(off_limits, recursive = TRUE, which = "strong")) + setdiff(packages, c(off_limits, off_limits_dep)) + } + + if (Sys.getenv("GITHUB_BASE_REF") != "") { + print(Sys.getenv("GITHUB_BASE_REF")) + has_diff <- (system("git diff ${{ github.event.pull_request.base.sha }}... | egrep '^[+][^+]' | grep -q ::") == 0) + if (has_diff) { + system("git diff ${{ github.event.pull_request.base.sha }}... | egrep '^[+][^+]' | grep -q ::") + packages <- get_deps() + } else { + writeLines("No changes using :: found, not checking without suggested packages") + packages <- character() + } + } else { + packages <- get_deps() + } + + if (length(packages) > 0) { + json <- paste0( + '{"package":[', + paste0('"', packages, '"', collapse = ","), + ']}' + ) + writeLines(json) + writeLines(paste0("matrix=", json), Sys.getenv("GITHUB_OUTPUT")) + } else { + writeLines("Package list empty!") + } + shell: Rscript {0} diff --git a/.github/workflows/dep-matrix/action.yml b/.github/workflows/dep-matrix/action.yml new file mode 100644 index 0000000..35dcb3c --- /dev/null +++ b/.github/workflows/dep-matrix/action.yml @@ -0,0 +1,134 @@ +name: "Actions to compute a matrix with all dependent packages" +outputs: + matrix: + description: "Generated matrix" + value: ${{ steps.set-matrix.outputs.matrix }} + +runs: + using: "composite" + steps: + - id: set-matrix + run: | + # Determine package dependencies + # From remotes + read_dcf <- function(path) { + fields <- colnames(read.dcf(path)) + as.list(read.dcf(path, keep.white = fields)[1, ]) + } + + re_match <- function(text, pattern, perl = TRUE, ...) { + + stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) + text <- as.character(text) + + match <- regexpr(pattern, text, perl = perl, ...) + + start <- as.vector(match) + length <- attr(match, "match.length") + end <- start + length - 1L + + matchstr <- substring(text, start, end) + matchstr[ start == -1 ] <- NA_character_ + + res <- data.frame( + stringsAsFactors = FALSE, + .text = text, + .match = matchstr + ) + + if (!is.null(attr(match, "capture.start"))) { + + gstart <- attr(match, "capture.start") + glength <- attr(match, "capture.length") + gend <- gstart + glength - 1L + + groupstr <- substring(text, gstart, gend) + groupstr[ gstart == -1 ] <- NA_character_ + dim(groupstr) <- dim(gstart) + + res <- cbind(groupstr, res, stringsAsFactors = FALSE) + } + + names(res) <- c(attr(match, "capture.names"), ".text", ".match") + class(res) <- c("tbl_df", "tbl", class(res)) + res + } + + dev_split_ref <- function(x) { + re_match(x, "^(?[^@#]+)(?[@#].*)?$") + } + + has_dev_dep <- function(package) { + cran_url <- "https://cloud.r-project.org" + + refs <- dev_split_ref(package) + url <- file.path(cran_url, "web", "packages", refs[["pkg"]], "DESCRIPTION") + + f <- tempfile() + on.exit(unlink(f)) + + utils::download.file(url, f) + desc <- read_dcf(f) + + url_fields <- c(desc$URL, desc$BugReports) + + if (length(url_fields) == 0) { + return(FALSE) + } + + pkg_urls <- unlist(strsplit(url_fields, "[[:space:]]*,[[:space:]]*")) + + # Remove trailing "/issues" from the BugReports URL + pkg_urls <- sub("/issues$", "", pkg_urls) + + valid_domains <- c("github[.]com", "gitlab[.]com", "bitbucket[.]org") + + parts <- + re_match(pkg_urls, + sprintf("^https?://(?%s)/(?%s)/(?%s)(?:/(?%s))?", + domain = paste0(valid_domains, collapse = "|"), + username = "[^/]+", + repo = "[^/@#]+", + subdir = "[^/@$ ]+" + ) + )[c("domain", "username", "repo", "subdir")] + + # Remove cases which don't match and duplicates + + parts <- unique(stats::na.omit(parts)) + + nrow(parts) == 1 + } + + if (!requireNamespace("desc", quietly = TRUE)) { + install.packages("desc") + } + + deps_df <- desc::desc_get_deps() + deps_df <- deps_df[deps_df$type %in% c("Depends", "Imports", "LinkingTo", "Suggests"), ] + + packages <- sort(deps_df$package) + packages <- intersect(packages, rownames(available.packages())) + + valid_dev_dep <- vapply(packages, has_dev_dep, logical(1)) + + # https://github.com/r-lib/remotes/issues/576 + valid_dev_dep[packages %in% c("igraph", "duckdb", "logging")] <- FALSE + + deps <- packages[valid_dev_dep] + if (any(!valid_dev_dep)) { + msg <- paste0( + "Could not determine development repository for packages: ", + paste(packages[!valid_dev_dep], collapse = ", ") + ) + writeLines(paste0("::warning::", msg)) + } + + json <- paste0( + '{"package":[', + paste0('"', deps, '"', collapse = ","), + ']}' + ) + writeLines(json) + writeLines(paste0("matrix=", json), Sys.getenv("GITHUB_OUTPUT")) + shell: Rscript {0} diff --git a/.github/workflows/fledge.yaml b/.github/workflows/fledge.yaml new file mode 100644 index 0000000..81c2d0c --- /dev/null +++ b/.github/workflows/fledge.yaml @@ -0,0 +1,58 @@ +name: fledge + +on: + # for manual triggers + workflow_dispatch: + # daily run + schedule: + - cron: "30 0 * * *" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.sha }}-${{ github.base_ref || '' }} + cancel-in-progress: true + +jobs: + check_fork: + runs-on: ubuntu-latest + outputs: + is_forked: ${{ steps.check.outputs.is_forked }} + steps: + - name: Check if the repo is forked + id: check + run: | + echo "is_forked=$(curl -s -H "Accept: application/vnd.github+json" -H 'Authorization: Bearer ${{ github.token }}' -H "X-GitHub-Api-Version: 2022-11-28" ${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY} | jq .fork)" >> $GITHUB_OUTPUT + + fledge: + runs-on: ubuntu-latest + needs: check_fork + if: needs.check_fork.outputs.is_forked == 'false' + permissions: + contents: write + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + FLEDGE_GHA_CI: true + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: ./.github/workflows/git-identity + + - uses: ./.github/workflows/install + with: + token: ${{ secrets.GITHUB_TOKEN }} + install-r: false + cache-version: fledge-1 + packages: cynkra/fledge + + - name: Bump version + run: | + if (fledge::bump_version(which = "dev", no_change_behavior = "noop")) { + fledge::finalize_version(push = TRUE) + } + shell: Rscript {0} + + - name: Check release + run: | + fledge:::release_after_cran_built_binaries() + shell: Rscript {0} diff --git a/.github/workflows/get-extra/action.yml b/.github/workflows/get-extra/action.yml new file mode 100644 index 0000000..84c56d9 --- /dev/null +++ b/.github/workflows/get-extra/action.yml @@ -0,0 +1,16 @@ +name: "Action to determine extra packages to be installed" +outputs: + packages: + description: "List of extra packages" + value: ${{ steps.get-extra.outputs.packages }} + +runs: + using: "composite" + steps: + - name: Get extra packages + id: get-extra + run: | + set -x + packages=$( ( grep Config/gha/extra-packages DESCRIPTION || true ) | cut -d " " -f 2) + echo packages=$packages >> $GITHUB_OUTPUT + shell: bash diff --git a/.github/workflows/git-identity/action.yml b/.github/workflows/git-identity/action.yml new file mode 100644 index 0000000..7234dab --- /dev/null +++ b/.github/workflows/git-identity/action.yml @@ -0,0 +1,11 @@ +name: "Actions to set up a Git identity" + +runs: + using: "composite" + steps: + - name: Configure Git identity + run: | + env | sort + git config --local user.name "$GITHUB_ACTOR" + git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" + shell: bash diff --git a/.github/workflows/install/action.yml b/.github/workflows/install/action.yml new file mode 100644 index 0000000..cf83bdb --- /dev/null +++ b/.github/workflows/install/action.yml @@ -0,0 +1,117 @@ +name: "Actions to run for installing R packages" +inputs: + token: + description: GitHub token, set to secrets.GITHUB_TOKEN + required: true + r-version: + description: Passed on to r-lib/actions/setup-r@v2 + required: false + default: release + install-r: + description: Passed on to r-lib/actions/setup-r@v2 + required: false + default: true + needs: + description: Passed on to r-lib/actions/setup-r-dependencies@v2 + required: false + default: "" + packages: + description: Passed on to r-lib/actions/setup-r-dependencies@v2 + required: false + default: deps::., any::sessioninfo + extra-packages: + description: Passed on to r-lib/actions/setup-r-dependencies@v2 + required: false + default: any::rcmdcheck + cache-version: + description: Passed on to r-lib/actions/setup-r-dependencies@v2 + required: false + default: 1 + +runs: + using: "composite" + steps: + - name: Set environment variables + run: | + echo "R_REMOTES_NO_ERRORS_FROM_WARNINGS=true" | tee -a $GITHUB_ENV + echo "R_KEEP_PKG_SOURCE=yes" | tee -a $GITHUB_ENV + echo "_R_CHECK_SYSTEM_CLOCK_=false" | tee -a $GITHUB_ENV + echo "_R_CHECK_FUTURE_FILE_TIMESTAMPS_=false" | tee -a $GITHUB_ENV + # prevent rgl issues because no X11 display is available + echo "RGL_USE_NULL=true" | tee -a $GITHUB_ENV + shell: bash + + - name: Update apt + if: runner.os == 'Linux' + run: | + sudo apt-get update + shell: bash + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ inputs.r-version }} + install-r: ${{ inputs.install-r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - id: get-extra + uses: ./.github/workflows/get-extra + + - uses: r-lib/actions/setup-r-dependencies@v2 + env: + GITHUB_PAT: ${{ inputs.token }} + with: + pak-version: devel + needs: ${{ inputs.needs }} + packages: ${{ inputs.packages }} + extra-packages: ${{ inputs.extra-packages }} ${{ ( matrix.config.covr && 'any::covr' ) || '' }} ${{ steps.get-extra.outputs.packages }} + cache-version: ${{ inputs.cache-version }} + + - name: Add pkg.lock to .gitignore + run: | + set -x + if ! [ -f .github/.gitignore ] || [ -z "$(grep '^/pkg.lock$' .github/.gitignore)" ]; then + echo /pkg.lock >> .github/.gitignore + fi + shell: bash + + - name: Add fake qpdf and checkbashisms + if: runner.os == 'Linux' + run: | + sudo ln -s $(which true) /usr/local/bin/qpdf + sudo ln -s $(which true) /usr/local/bin/checkbashisms + shell: bash + + - name: Install ccache + uses: krlmlr/ccache-action@parallel-dir + with: + max-size: 10G + verbose: 1 + save: false + restore: false + + - name: Use ccache for compiling R code, and parallelize + run: | + mkdir -p ~/.R + echo 'CC := ccache $(CC)' >> ~/.R/Makevars + echo 'CXX := ccache $(CXX)' >> ~/.R/Makevars + echo 'CXX11 := ccache $(CXX11)' >> ~/.R/Makevars + echo 'CXX14 := ccache $(CXX14)' >> ~/.R/Makevars + echo 'CXX17 := ccache $(CXX17)' >> ~/.R/Makevars + echo 'MAKEFLAGS = -j2' >> ~/.R/Makevars + cat ~/.R/Makevars + + echo 'CCACHE_SLOPPINESS=locale,time_macros' | tee -a $GITHUB_ENV + + # echo 'CCACHE_DEBUG=true' | tee -a $GITHUB_ENV + # echo "CCACHE_DEBUGDIR=$(dirname $(pwd))/ccache-debug" | tee -a $GITHUB_ENV + # mkdir -p $(dirname $(pwd))/.ccache-debug + + echo 'PKG_BUILD_EXTRA_FLAGS=false' | tee -a $GITHUB_ENV + + # Repair + git rm -rf .ccache || true + rm -rf .ccache + shell: bash diff --git a/.github/workflows/lock.yaml b/.github/workflows/lock.yaml new file mode 100644 index 0000000..5b19556 --- /dev/null +++ b/.github/workflows/lock.yaml @@ -0,0 +1,19 @@ +name: "Lock threads" + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + lock: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v4 + with: + github-token: ${{ github.token }} + issue-lock-inactive-days: "365" + issue-lock-reason: "" + issue-lock-comment: > + This old thread has been automatically locked. If you think you have + found something related to this, please open a new issue and link to this + old issue if necessary. diff --git a/.github/workflows/pkgdown-build/action.yml b/.github/workflows/pkgdown-build/action.yml new file mode 100644 index 0000000..381d067 --- /dev/null +++ b/.github/workflows/pkgdown-build/action.yml @@ -0,0 +1,9 @@ +name: "Action to build a pkgdown website" + +runs: + using: "composite" + steps: + - name: Build site + run: | + pkgdown::build_site() + shell: Rscript {0} diff --git a/.github/workflows/pkgdown-deploy/action.yml b/.github/workflows/pkgdown-deploy/action.yml new file mode 100644 index 0000000..18d0206 --- /dev/null +++ b/.github/workflows/pkgdown-deploy/action.yml @@ -0,0 +1,12 @@ +name: "Action to deploy a pkgdown website" + +runs: + using: "composite" + steps: + - name: Deploy site + uses: nick-fields/retry@v2 + with: + timeout_minutes: 15 + max_attempts: 10 + command: | + R -q -e 'pkgdown::deploy_to_branch(new_process = FALSE)' diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml new file mode 100644 index 0000000..7400040 --- /dev/null +++ b/.github/workflows/pkgdown.yaml @@ -0,0 +1,54 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Also included in R-CMD-check.yaml, this workflow only listens to pushes to branches +# that start with "docs*" +on: + push: + branches: + - "docs*" + - "cran-*" + workflow_dispatch: + +name: pkgdown + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.sha }}-${{ github.base_ref || '' }} + cancel-in-progress: true + +jobs: + pkgdown: + runs-on: ubuntu-latest + + name: "pkgdown" + + # Begin custom: services + # End custom: services + + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/workflows/rate-limit + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: ./.github/workflows/git-identity + if: github.event_name == 'push' + + - uses: ./.github/workflows/custom/before-install + if: hashFiles('.github/workflows/custom/before-install/action.yml') != '' + + - uses: ./.github/workflows/install + with: + token: ${{ secrets.GITHUB_TOKEN }} + install-r: false + cache-version: pkgdown-2 + needs: website + extra-packages: r-lib/pkgdown local::. + + - uses: ./.github/workflows/custom/after-install + if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' + + - uses: ./.github/workflows/pkgdown-build + if: github.event_name != 'push' + + - uses: ./.github/workflows/pkgdown-deploy + if: github.event_name == 'push' diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml new file mode 100644 index 0000000..3ce95aa --- /dev/null +++ b/.github/workflows/pr-commands.yaml @@ -0,0 +1,103 @@ +on: + issue_comment: + types: [created] +name: Commands +jobs: + document: + if: startsWith(github.event.comment.body, '/document') + name: document + # macos is actually better here due to native binary packages + runs-on: macos-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + - uses: r-lib/actions/pr-fetch@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - uses: r-lib/actions/setup-r@master + with: + install-r: false + - name: Configure Git identity + run: | + env | sort + git config --local user.name "$GITHUB_ACTOR" + git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" + shell: bash + - name: Install dependencies + run: | + install.packages(c("remotes", "roxygen2"), type = "binary") + remotes::install_deps(dependencies = TRUE) + shell: Rscript {0} + - name: Document + run: | + roxygen2::roxygenise() + shell: Rscript {0} + - name: commit + run: | + if [ -n "$(git status --porcelain man/ NAMESPACE)" ]; then + git add man/ NAMESPACE + git commit -m 'Document' + fi + - uses: r-lib/actions/pr-push@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + style: + if: startsWith(github.event.comment.body, '/style') + name: style + # macos is actually better here due to native binary packages + runs-on: macos-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + - uses: r-lib/actions/pr-fetch@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - uses: r-lib/actions/setup-r@master + with: + install-r: false + - name: Configure Git identity + run: | + env | sort + git config --local user.name "$GITHUB_ACTOR" + git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" + shell: bash + - name: Install dependencies + run: | + install.packages(c("styler", "roxygen2"), type = "binary") + shell: Rscript {0} + - name: Style + run: | + styler::style_pkg(strict = FALSE) + shell: Rscript {0} + - name: commit + run: | + if [ -n "$(git status --porcelain '*.R' '*.Rmd')" ]; then + git add '*.R' '*.Rmd' + git commit -m 'Style' + fi + - uses: r-lib/actions/pr-push@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + merge: + if: startsWith(github.event.comment.body, '/merge') + name: merge + runs-on: ubuntu-22.04 + steps: + - name: Create and merge pull request + run: | + set -exo pipefail + PR_DETAILS=$( curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.issue.number }} ) + echo "$PR_DETAILS" | jq . + PR_BASE=$(echo "$PR_DETAILS" | jq -r .base.ref) + PR_HEAD=$(echo "$PR_DETAILS" | jq -r .head.ref) + PR_URL=$(curl -s -X POST --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" --data '{ "head": "'$PR_BASE'", "base": "'$PR_HEAD'", "title": "Merge back PR target branch", "body": "Target: #${{ github.event.issue.number }}" }' https://api.github.com/repos/${{ github.repository }}/pulls | jq -r .url ) + echo $PR_URL + # Merging here won't run CI/CD + # curl -s -X PUT --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" $PR_URL/merge + # A mock job just to ensure we have a successful build status + finish: + runs-on: ubuntu-22.04 + steps: + - run: true diff --git a/.github/workflows/rate-limit/action.yml b/.github/workflows/rate-limit/action.yml new file mode 100644 index 0000000..8180fe4 --- /dev/null +++ b/.github/workflows/rate-limit/action.yml @@ -0,0 +1,13 @@ +name: "Check GitHub rate limits" +inputs: + token: # id of input + description: GitHub token, pass secrets.GITHUB_TOKEN + required: true + +runs: + using: "composite" + steps: + - name: Check rate limits + run: | + curl -s --header "authorization: Bearer ${{ inputs.token }}" https://api.github.com/rate_limit + shell: bash diff --git a/.github/workflows/revdep.yaml b/.github/workflows/revdep.yaml new file mode 100644 index 0000000..4a0d511 --- /dev/null +++ b/.github/workflows/revdep.yaml @@ -0,0 +1,213 @@ +# This workflow creates many jobs, run only when a branch is created +on: + push: + branches: + - "revdep*" # never run automatically on main branch + +name: revdep + +jobs: + matrix: + runs-on: ubuntu-22.04 + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + + name: Collect revdeps + + env: + R_REMOTES_NO_ERRORS_FROM_WARNINGS: true + RSPM: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + # prevent rgl issues because no X11 display is available + RGL_USE_NULL: true + # Begin custom: env vars + # End custom: env vars + + steps: + - name: Check rate limits + run: | + curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit + shell: bash + + - uses: actions/checkout@v4 + + # FIXME: Avoid reissuing succesful jobs + # https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#list-jobs-for-a-workflow-run + # https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#workflow-runs + - id: set-matrix + run: | + package <- read.dcf("DESCRIPTION")[, "Package"][[1]] + deps <- tools:::package_dependencies(package, reverse = TRUE, which = c("Depends", "Imports", "LinkingTo", "Suggests"))[[1]] + json <- paste0( + '{"package":[', + paste0('"', deps, '"', collapse = ","), + ']}' + ) + writeLines(json) + writeLines(paste0("matrix=", json), Sys.getenv("GITHUB_OUTPUT")) + shell: Rscript {0} + + check-matrix: + runs-on: ubuntu-22.04 + needs: matrix + steps: + - name: Install json2yaml + run: | + sudo npm install -g json2yaml + + - name: Check matrix definition + run: | + matrix='${{ needs.matrix.outputs.matrix }}' + echo $matrix + echo $matrix | jq . + echo $matrix | json2yaml + + R-CMD-check: + needs: matrix + + runs-on: ubuntu-22.04 + + name: ${{ matrix.package }} + + # Begin custom: services + # End custom: services + + strategy: + fail-fast: false + matrix: ${{fromJson(needs.matrix.outputs.matrix)}} + + env: + R_REMOTES_NO_ERRORS_FROM_WARNINGS: true + RSPM: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + # prevent rgl issues because no X11 display is available + RGL_USE_NULL: true + # Begin custom: env vars + # End custom: env vars + + steps: + - name: Check rate limits + run: | + curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit + shell: bash + + - uses: actions/checkout@v4 + + # Begin custom: before install + # End custom: before install + + - name: Use RSPM + run: | + mkdir -p /home/runner/work/_temp/Library + echo 'local({release <- system2("lsb_release", "-sc", stdout = TRUE); options(repos=c(CRAN = paste0("https://packagemanager.rstudio.com/all/__linux__/", release, "/latest")), HTTPUserAgent = sprintf("R/%s R (%s)", getRversion(), paste(getRversion(), R.version$platform, R.version$arch, R.version$os)))}); .libPaths("/home/runner/work/_temp/Library")' | sudo tee /etc/R/Rprofile.site + + - name: Install remotes + run: | + if (!requireNamespace("curl", quietly = TRUE)) install.packages("curl") + if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") + shell: Rscript {0} + + - uses: r-lib/actions/setup-pandoc@v2 + + - name: Install system dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update -y + Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "22.04")); package <- "${{ matrix.package }}"; deps <- tools::package_dependencies(package, which = "Suggests")[[1]]; lapply(c(package, deps), function(x) { writeLines(remotes::system_requirements("ubuntu", "22.04", package = x)) })' | sort | uniq > .github/deps.sh + cat .github/deps.sh + sudo sh < .github/deps.sh + + - name: Install package + run: | + package <- "${{ matrix.package }}" + install.packages(package, dependencies = TRUE) + remotes::install_cran("rcmdcheck") + shell: Rscript {0} + + - name: Session info old + run: | + options(width = 100) + if (!requireNamespace("sessioninfo", quietly = TRUE)) install.packages("sessioninfo") + pkgs <- installed.packages()[, "Package"] + sessioninfo::session_info(pkgs, include_base = TRUE) + shell: Rscript {0} + + # Begin custom: after install + # End custom: after install + + - name: Check old + env: + _R_CHECK_CRAN_INCOMING_: false + _R_CHECK_SYSTEM_CLOCK_: false + _R_CHECK_FUTURE_FILE_TIMESTAMPS_: false + # Avoid downloading binary package from RSPM + run: | + package <- "${{ matrix.package }}" + options(HTTPUserAgent = "gha") + path <- download.packages(package, destdir = ".github")[, 2] + print(path) + + dir <- file.path("revdep", package) + dir.create(dir, showWarnings = FALSE, recursive = TRUE) + check <- rcmdcheck::rcmdcheck(path, args = c("--no-manual", "--as-cran"), error_on = "never", check_dir = file.path(dir, "check")) + file.rename(file.path(dir, "check"), file.path(dir, "old")) + saveRDS(check, file.path(dir, "old.rds")) + shell: Rscript {0} + + - name: Install local package + run: | + remotes::install_local(".", force = TRUE) + shell: Rscript {0} + + - name: Session info new + run: | + options(width = 100) + pkgs <- installed.packages()[, "Package"] + sessioninfo::session_info(pkgs, include_base = TRUE) + shell: Rscript {0} + + - name: Check new + env: + _R_CHECK_CRAN_INCOMING_: false + _R_CHECK_SYSTEM_CLOCK_: false + _R_CHECK_FUTURE_FILE_TIMESTAMPS_: false + run: | + package <- "${{ matrix.package }}" + path <- dir(".github", pattern = paste0("^", package), full.names = TRUE)[[1]] + print(path) + + dir <- file.path("revdep", package) + check <- rcmdcheck::rcmdcheck(path, args = c("--no-manual", "--as-cran"), error_on = "never", check_dir = file.path(dir, "check")) + file.rename(file.path(dir, "check"), file.path(dir, "new")) + saveRDS(check, file.path(dir, "new.rds")) + shell: Rscript {0} + + - name: Compare + run: | + package <- "${{ matrix.package }}" + dir <- file.path("revdep", package) + old <- readRDS(file.path(dir, "old.rds")) + new <- readRDS(file.path(dir, "new.rds")) + compare <- rcmdcheck::compare_checks(old, new) + compare + cmp <- compare$cmp + if (!identical(cmp[cmp$which == "old", "output"], cmp[cmp$which == "new", "output"])) { + if (!requireNamespace("waldo", quietly = TRUE)) install.packages("waldo") + print(waldo::compare(old, new)) + + stop("Check output differs.") + } + shell: Rscript {0} + + - name: Upload check results + if: failure() + uses: actions/upload-artifact@main + with: + name: ${{ matrix.package }}-results + path: revdep/${{ matrix.package }} + + - name: Check rate limits + if: always() + run: | + curl -s --header "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit + shell: bash diff --git a/.github/workflows/roxygenize/action.yml b/.github/workflows/roxygenize/action.yml new file mode 100644 index 0000000..ee1d652 --- /dev/null +++ b/.github/workflows/roxygenize/action.yml @@ -0,0 +1,9 @@ +name: "Action to create documentation with roxygen2" + +runs: + using: "composite" + steps: + - name: Roxygenize + run: | + try(roxygen2::roxygenize()) + shell: Rscript {0} diff --git a/.github/workflows/style/action.yml b/.github/workflows/style/action.yml new file mode 100644 index 0000000..b209d9e --- /dev/null +++ b/.github/workflows/style/action.yml @@ -0,0 +1,71 @@ +name: "Action to auto-style a package" + +runs: + using: "composite" + steps: + - name: Check styler options + id: check + run: | + set -x + scope=$( ( grep Config/autostyle/scope DESCRIPTION || true ) | cut -d " " -f 2) + strict=$( ( grep Config/autostyle/strict DESCRIPTION || true ) | cut -d " " -f 2) + rmd=$( ( grep Config/autostyle/rmd DESCRIPTION || true ) | cut -d " " -f 2) + echo scope=$scope >> $GITHUB_OUTPUT + echo strict=$strict >> $GITHUB_OUTPUT + echo rmd=$rmd >> $GITHUB_OUTPUT + shell: bash + + - uses: actions/cache@v3 + if: ${{ steps.check.outputs.scope }} + with: + path: | + ~/.cache/R/R.cache + key: ${{ runner.os }}-2-${{ github.run_id }}- + restore-keys: | + ${{ runner.os }}-2- + + - name: Imprint run ID + if: ${{ steps.check.outputs.scope }} + run: | + mkdir -p ~/.cache/R/R.cache/styler + touch ~/.cache/R/R.cache/${{ github.run_id }} + shell: bash + + - name: Show cache + if: ${{ steps.check.outputs.scope }} + run: | + ls -l ~/.cache/R/R.cache + ls -l ~/.cache/R/R.cache/styler + shell: bash + + - name: Enable styler cache + if: ${{ steps.check.outputs.scope }} + run: | + styler::cache_activate(verbose = TRUE) + shell: Rscript {0} + + - name: Run styler + if: ${{ steps.check.outputs.scope }} + run: | + strict <- as.logical("${{ steps.check.outputs.strict }}") + if (is.na(strict)) { + strict <- FALSE + } + rmd <- as.logical("${{ steps.check.outputs.rmd }}") + if (is.na(rmd)) { + rmd <- TRUE + } + styler::style_pkg( + scope = "${{ steps.check.outputs.scope }}", + strict = strict, + filetype = c("R", "Rprofile", if (rmd) c("Rmd", "Rmarkdown", "Rnw", "Qmd")) + ) + shell: Rscript {0} + + - name: Show cache again + if: ${{ steps.check.outputs.scope }} + run: | + ls -l ~/.cache/R/R.cache + ls -l ~/.cache/R/R.cache/styler + gdu -s --inodes ~/.cache/R/R.cache/styler/* || du -s --inodes ~/.cache/R/R.cache/styler/* + shell: bash diff --git a/.github/workflows/update-snapshots/action.yml b/.github/workflows/update-snapshots/action.yml new file mode 100644 index 0000000..2e1db0e --- /dev/null +++ b/.github/workflows/update-snapshots/action.yml @@ -0,0 +1,82 @@ +name: "Action to create pull requests for updated testthat snapshots" +description: > + This action will run `testthat::test_local()` for tests that seem to use snapshots, + this is determined by reading and grepping the test files. + If the tests are failing, snapshots are updated, and a pull request is opened. + +runs: + using: "composite" + steps: + - name: Run tests on test files that use snapshots + id: run-tests + run: | + ## -- Run tests on test files that use snapshots -- + rx <- "^test-(.*)[.][rR]$" + files <- dir("tests/testthat", pattern = rx) + has_snapshot <- vapply(files, function(.x) any(grepl("snapshot", readLines(file.path("tests/testthat", .x)), fixed = TRUE)), logical(1)) + if (any(has_snapshot)) { + patterns <- gsub(rx, "^\\1$", files[has_snapshot]) + pattern <- paste0(patterns, collapse = "|") + tryCatch( + { + result <- as.data.frame(testthat::test_local(pattern = pattern, reporter = "silent", stop_on_failure = FALSE)) + failures <- result[result$failed + result$warning > 0, ] + if (nrow(failures) > 0) { + writeLines("Snapshot tests failed/warned.") + print(failures[names(failures) != "result"]) + print(failures$result) + testthat::snapshot_accept() + writeLines("changed=true", Sys.getenv("GITHUB_OUTPUT")) + } else { + writeLines("Snapshot tests ran successfully.") + } + }, + error = print + ) + } else { + writeLines("No snapshots found.") + } + shell: Rscript {0} + + - name: Add snapshots to Git + if: ${{ steps.run-tests.outputs.changed }} + run: | + ## -- Add snapshots to Git -- + mkdir -p tests/testthat/_snaps + git add -- tests/testthat/_snaps + shell: bash + + - name: Check changed files + if: ${{ steps.run-tests.outputs.changed }} + id: check-changed + run: | + echo "changed=$(git status --porcelain -- tests/testthat/_snaps | head -n 1)" >> $GITHUB_OUTPUT + shell: bash + + - name: Derive branch name + if: ${{ steps.check-changed.outputs.changed }} + id: matrix-desc + run: | + config=$(echo '${{ toJSON(matrix) }}' | jq -c .) + echo "text=$(echo ${config})" >> $GITHUB_OUTPUT + echo "branch=$(echo ${config} | sed -r 's/[^0-9a-zA-Z]+/-/g;s/^-//;s/-$//')" >> $GITHUB_OUTPUT + shell: bash + + - name: Create pull request + if: ${{ steps.check-changed.outputs.changed }} + id: cpr + uses: peter-evans/create-pull-request@v5 + with: + base: ${{ github.head_ref }} + branch: snapshot-${{ github.ref_name }}-${{ github.job }}-${{ steps.matrix-desc.outputs.branch }} + delete-branch: true + title: Snapshot updates for ${{ github.job }} (${{ steps.matrix-desc.outputs.text }}) + body: "Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action${{ github.event.number && format(' for #{0}', github.event.number) || '' }}." + add-paths: | + tests/testthat/_snaps + + - name: Fail if pull request created + if: ${{ steps.cpr.outputs.pull-request-number }} + run: | + false + shell: bash diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c904820 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.Rhistory +.Rproj.user diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..0343527 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,25 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for +everyone, regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. + +Examples of unacceptable behavior by participants include the use of sexual language or +imagery, derogatory comments or personal attacks, trolling, public or private harassment, +insults, or other unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, +commits, code, wiki edits, issues, and other contributions that are not aligned to this +Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed +from the project team. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by +opening an issue or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the Contributor Covenant +(https://www.contributor-covenant.org), version 1.0.0, available at +https://contributor-covenant.org/version/1/0/0/. diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..9694c82 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,78 @@ +Package: RKazam +Title: Boilerplate for implementing a DBI back end +Version: 0.0.0.9015 +Authors@R: + c(person(given = "Kirill", + family = "M\u00fcller", + role = c("aut", "cre"), + email = "kirill@cynkra.com", + comment = c(ORCID = "0000-0002-1416-3412")), + person(given = "R Consortium", + role = "fnd") + ) +Description: A dummy DBI back end that provides access to a + hypothetical data source named "Kazam", intended to be used as + boilerplate for implementing DBI back ends from scratch. +License: CC0 +URL: https://rkazam.r-dbi.org, https://github.com/r-dbi/RKazam +Depends: + R (>= 3.0.0) +Imports: + DBI (>= 1.2.0), + methods, + testthat +Suggests: + covr, + DBItest (>= 1.8.0) +Remotes: + r-dbi/DBI +Config/Needs/website: r-dbi/dbitemplate +Encoding: UTF-8 +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.3.1 +Collate: + 'RKazam-package.R' + 'Driver.R' + 'Connection.R' + 'Result.R' + 'ResultArrow.R' + 'dbAppendTable_Connection_character_data.frame.R' + 'dbBegin_Connection.R' + 'dbBind_Result.R' + 'dbClearResult_Result.R' + 'dbClearResult_ResultArrow.R' + 'dbColumnInfo_Result.R' + 'dbCommit_Connection.R' + 'dbConnect_Driver.R' + 'dbDataType_Connection.R' + 'dbDataType_Driver.R' + 'dbDataType_Driver_list.R' + 'dbDisconnect_Connection.R' + 'dbExistsTable_Connection_character.R' + 'dbFetchArrow_ResultArrow.R' + 'dbFetch_Result.R' + 'dbGetInfo_Connection.R' + 'dbGetInfo_Driver.R' + 'dbGetInfo_Result.R' + 'dbGetRowCount_Result.R' + 'dbGetRowsAffected_Result.R' + 'dbGetStatement_Result.R' + 'dbHasCompleted_Result.R' + 'dbIsValid_Connection.R' + 'dbIsValid_Driver.R' + 'dbIsValid_Result.R' + 'dbListFields_Connection_character.R' + 'dbListTables_Connection.R' + 'dbQuoteIdentifier_Connection_character.R' + 'dbQuoteString_Connection_character.R' + 'dbRemoveTable_Connection_character.R' + 'dbRollback_Connection.R' + 'dbSendQueryArrow_Connection.R' + 'dbSendQuery_Connection_character.R' + 'dbSendStatement_Connection_character.R' + 'dbWriteTable_Connection_character_data.frame.R' + 'show_Connection.R' + 'show_Driver.R' + 'show_Result.R' +Config/autostyle/scope: line_breaks +Config/autostyle/strict: false diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..139c68e --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,43 @@ +## creative commons + +# CC0 1.0 Universal + +CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. + +### Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. + +1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. + +2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. + +3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. + +4. __Limitations and Disclaimers.__ + + a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..38d8e1f --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,62 @@ +# Generated by roxygen2: do not edit by hand + +export(Id) +export(Kazam) +export(dbAppendTable) +export(dbCanConnect) +export(dbCreateTable) +export(dbExecute) +export(dbGetQuery) +export(dbIsReadOnly) +export(dbListObjects) +export(dbQuoteLiteral) +export(dbReadTable) +export(dbUnquoteIdentifier) +export(dbWithTransaction) +exportClasses(KazamConnection) +exportClasses(KazamDriver) +exportClasses(KazamResult) +exportClasses(KazamResultArrow) +exportMethods(dbAppendTable) +exportMethods(dbBegin) +exportMethods(dbBind) +exportMethods(dbClearResult) +exportMethods(dbColumnInfo) +exportMethods(dbCommit) +exportMethods(dbConnect) +exportMethods(dbDataType) +exportMethods(dbDisconnect) +exportMethods(dbExistsTable) +exportMethods(dbFetch) +exportMethods(dbFetchArrow) +exportMethods(dbGetInfo) +exportMethods(dbGetRowCount) +exportMethods(dbGetRowsAffected) +exportMethods(dbGetStatement) +exportMethods(dbHasCompleted) +exportMethods(dbIsValid) +exportMethods(dbListFields) +exportMethods(dbListTables) +exportMethods(dbQuoteIdentifier) +exportMethods(dbQuoteString) +exportMethods(dbRemoveTable) +exportMethods(dbRollback) +exportMethods(dbSendQuery) +exportMethods(dbSendQueryArrow) +exportMethods(dbSendStatement) +exportMethods(dbWriteTable) +exportMethods(show) +import(DBI) +import(methods) +importFrom(DBI,Id) +importFrom(DBI,dbAppendTable) +importFrom(DBI,dbCanConnect) +importFrom(DBI,dbCreateTable) +importFrom(DBI,dbExecute) +importFrom(DBI,dbGetQuery) +importFrom(DBI,dbIsReadOnly) +importFrom(DBI,dbListObjects) +importFrom(DBI,dbQuoteLiteral) +importFrom(DBI,dbReadTable) +importFrom(DBI,dbUnquoteIdentifier) +importFrom(DBI,dbWithTransaction) diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..3bddff5 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,104 @@ + + +# RKazam 0.0.0.9015 (2024-01-24) + +- Internal changes only. + + +# RKazam 0.0.0.9014 (2024-01-15) + +- Internal changes only. + + +# RKazam 0.0.0.9013 (2023-12-26) + +- Internal changes only. + + +# RKazam 0.0.0.9012 (2023-12-23) + +## Chore + +- Bump dependencies. + +- Add Aviator configuration. + +## Documentation + +- Use dbitemplate (@maelle, #22). + + +# RKazam 0.0.0.9011 (2023-12-18) + +- Internal changes only. + + +# RKazam 0.0.0.9010 (2023-11-10) + +## Testing + +- Skip helper if DBItest is not installed (#21). + + +# RKazam 0.0.0.9009 (2023-11-06) + +## Chore + +- Add Aviator configuration. + +## Testing + +- Only run if DBItest is installed (#20). + + +# RKazam 0.0.0.9008 (2023-10-09) + +## Features + +- Bring back improvements from adbc package (#19). + + +# RKazam 0.0.0.9007 (2023-03-24) + +- Internal changes only. + + +# RKazam 0.0.0.9006 (2023-02-17) + +- Internal changes only. + + +# RKazam 0.0.0.9005 (2022-12-30) + +- Internal changes only. + + +# RKazam 0.0.0.9004 (2022-12-24) + +- Harmonize yaml formatting. + +- Revert changes to matrix section. + + +# RKazam 0.0.0.9003 (2021-12-18) + +- Make method definition more similar to S3 (#14). +- Compatibility with DBItest 1.7.2 (#13). +- Switch to CC0 license (#7). +- Prepare for CII badge (#6). +- Add comment pointing to implementations that help grow a data frame (#3). + + +# RKazam 0.0.0.9002 (2020-12-22) + +- Converted to template repository on GitHub (#8). + + +# RKazam 0.0.0.9001 (2020-12-05) + +- Switch to GitHub Actions (#9). +- Prefer `testthat::skip()` over `skip()` so that tests run cleanly (#5). +- Add ellipsis `...` to the signature of all DBI methods. +- Travis tests pass. +- Enable Travis CI. +- Compatibility with current DBI: Use default method for `dbGetInfo(DBIResult)`. diff --git a/R/Connection.R b/R/Connection.R new file mode 100644 index 0000000..3caa4c7 --- /dev/null +++ b/R/Connection.R @@ -0,0 +1,47 @@ +#' @include Driver.R +NULL + +KazamConnection <- function() { + # TODO: Add arguments + new("KazamConnection") +} + +#' @rdname DBI +#' @export +setClass( + "KazamConnection", + contains = "DBIConnection", + slots = list( + # TODO: Add slots + ) +) + +#' @export +DBI::dbIsReadOnly + +#' @export +DBI::dbQuoteLiteral + +#' @export +DBI::dbUnquoteIdentifier + +#' @export +DBI::dbGetQuery + +#' @export +DBI::dbExecute + +#' @export +DBI::dbReadTable + +#' @export +DBI::dbCreateTable + +#' @export +DBI::dbAppendTable + +#' @export +DBI::dbListObjects + +#' @export +DBI::dbWithTransaction diff --git a/R/Driver.R b/R/Driver.R new file mode 100644 index 0000000..318c506 --- /dev/null +++ b/R/Driver.R @@ -0,0 +1,38 @@ +#' @include RKazam-package.R +NULL + +#' DBI methods +#' +#' Implementations of pure virtual functions defined in the `DBI` package. +#' @name DBI +NULL + +#' Kazam driver +#' +#' TBD. +#' +#' @export +#' @examples +#' \dontrun{ +#' #' library(DBI) +#' RKazam::Kazam() +#' } +Kazam <- function() { + new("KazamDriver") +} + +#' @rdname DBI +#' @export +setClass( + "KazamDriver", + contains = "DBIDriver", + slots = list( + # TODO: Add slots + ) +) + +#' @export +DBI::dbCanConnect + +#' @export +DBI::Id diff --git a/R/RKazam-package.R b/R/RKazam-package.R new file mode 100644 index 0000000..05a7c82 --- /dev/null +++ b/R/RKazam-package.R @@ -0,0 +1,8 @@ +#' @keywords internal +"_PACKAGE" + +## usethis namespace: start +#' @import DBI +#' @import methods +## usethis namespace: end +NULL diff --git a/R/Result.R b/R/Result.R new file mode 100644 index 0000000..f62eed5 --- /dev/null +++ b/R/Result.R @@ -0,0 +1,21 @@ +#' @include Connection.R +NULL + +KazamResult <- function(connection, statement) { + # TODO: Initialize result + new("KazamResult", + connection = connection, + statement = statement + ) +} + +#' @rdname DBI +#' @export +setClass( + "KazamResult", + contains = "DBIResult", + slots = list( + connection = "KazamConnection", + statement = "character" + ) +) diff --git a/R/ResultArrow.R b/R/ResultArrow.R new file mode 100644 index 0000000..746c74e --- /dev/null +++ b/R/ResultArrow.R @@ -0,0 +1,21 @@ +#' @include Connection.R +NULL + +KazamResultArrow <- function(connection, statement) { + # TODO: Initialize result + new("KazamResultArrow", + connection = connection, + statement = statement + ) +} + +#' @rdname DBI +#' @export +setClass( + "KazamResultArrow", + contains = "DBIResultArrow", + slots = list( + connection = "KazamConnection", + statement = "character" + ) +) diff --git a/R/dbAppendTable_Connection_character_data.frame.R b/R/dbAppendTable_Connection_character_data.frame.R new file mode 100644 index 0000000..6bd1f91 --- /dev/null +++ b/R/dbAppendTable_Connection_character_data.frame.R @@ -0,0 +1,22 @@ +#' @rdname DBI +#' @usage NULL +dbAppendTable_KazamConnection <- function(conn, name, value, ..., row.names = NULL) { + # FIXME: Remove when parameterized binding is implemented + + if (!is.null(row.names)) { + stop("Can't pass `row.names` to `dbAppendTable()`", call. = FALSE) + } + stopifnot(is.data.frame(value)) + + query <- sqlAppendTable( + con = conn, + table = name, + values = value, + row.names = row.names, + ... + ) + dbExecute(conn, query) +} +#' @rdname DBI +#' @export +setMethod("dbAppendTable", signature("KazamConnection"), dbAppendTable_KazamConnection) diff --git a/R/dbBegin_Connection.R b/R/dbBegin_Connection.R new file mode 100644 index 0000000..1083dab --- /dev/null +++ b/R/dbBegin_Connection.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbBegin +#' @usage NULL +dbBegin_KazamConnection <- function(conn, ...) { + testthat::skip("Not yet implemented: dbBegin(Connection)") +} +#' @rdname DBI +#' @export +setMethod("dbBegin", "KazamConnection", dbBegin_KazamConnection) diff --git a/R/dbBind_Result.R b/R/dbBind_Result.R new file mode 100644 index 0000000..2ce060c --- /dev/null +++ b/R/dbBind_Result.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbBind +#' @usage NULL +dbBind_KazamResult <- function(res, params, ...) { + testthat::skip("Not yet implemented: dbBind(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbBind", "KazamResult", dbBind_KazamResult) diff --git a/R/dbClearResult_Result.R b/R/dbClearResult_Result.R new file mode 100644 index 0000000..d87c50b --- /dev/null +++ b/R/dbClearResult_Result.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbClearResult +#' @usage NULL +dbClearResult_KazamResult <- function(res, ...) { + testthat::skip("Not yet implemented: dbClearResult(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbClearResult", "KazamResult", dbClearResult_KazamResult) diff --git a/R/dbClearResult_ResultArrow.R b/R/dbClearResult_ResultArrow.R new file mode 100644 index 0000000..fa641b8 --- /dev/null +++ b/R/dbClearResult_ResultArrow.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams DBI::dbClearResult +#' @usage NULL +dbClearResult_KazamResultArrow <- function(res, ...) { + # TODO: Implement as needed, or remove (default DBI implementation exists) + dbClearResult_KazamResult(res) +} +#' @rdname DBI +#' @export +setMethod("dbClearResult", "KazamResultArrow", dbClearResult_KazamResultArrow) diff --git a/R/dbColumnInfo_Result.R b/R/dbColumnInfo_Result.R new file mode 100644 index 0000000..9a2c720 --- /dev/null +++ b/R/dbColumnInfo_Result.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbColumnInfo +#' @usage NULL +dbColumnInfo_KazamResult <- function(res, ...) { + testthat::skip("Not yet implemented: dbColumnInfo(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbColumnInfo", "KazamResult", dbColumnInfo_KazamResult) diff --git a/R/dbCommit_Connection.R b/R/dbCommit_Connection.R new file mode 100644 index 0000000..89ac625 --- /dev/null +++ b/R/dbCommit_Connection.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbCommit +#' @usage NULL +dbCommit_KazamConnection <- function(conn, ...) { + testthat::skip("Not yet implemented: dbCommit(Connection)") +} +#' @rdname DBI +#' @export +setMethod("dbCommit", "KazamConnection", dbCommit_KazamConnection) diff --git a/R/dbConnect_Driver.R b/R/dbConnect_Driver.R new file mode 100644 index 0000000..806e0e7 --- /dev/null +++ b/R/dbConnect_Driver.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams DBI::dbConnect +#' @usage NULL +dbConnect_KazamDriver <- function(drv, ...) { + # TODO: Implement + KazamConnection() +} +#' @rdname DBI +#' @export +setMethod("dbConnect", "KazamDriver", dbConnect_KazamDriver) diff --git a/R/dbDataType_Connection.R b/R/dbDataType_Connection.R new file mode 100644 index 0000000..cc5a3f6 --- /dev/null +++ b/R/dbDataType_Connection.R @@ -0,0 +1,12 @@ +#' @rdname DBI +#' @inheritParams DBI::dbDataType +#' @usage NULL +dbDataType_KazamConnection <- function(dbObj, obj, ...) { + tryCatch( + callNextMethod(...), + error = function(e) testthat::skip("Not yet implemented: dbDataType(Connection)") + ) +} +#' @rdname DBI +#' @export +setMethod("dbDataType", "KazamConnection", dbDataType_KazamConnection) diff --git a/R/dbDataType_Driver.R b/R/dbDataType_Driver.R new file mode 100644 index 0000000..7dfffc5 --- /dev/null +++ b/R/dbDataType_Driver.R @@ -0,0 +1,13 @@ +#' @rdname DBI +#' @inheritParams DBI::dbDataType +#' @usage NULL +dbDataType_KazamDriver <- function(dbObj, obj, ...) { + # Optional: Can remove this if all data types conform to SQL-92 + tryCatch( + callNextMethod(...), + error = function(e) testthat::skip("Not yet implemented: dbDataType(Driver)") + ) +} +#' @rdname DBI +#' @export +setMethod("dbDataType", "KazamDriver", dbDataType_KazamDriver) diff --git a/R/dbDataType_Driver_list.R b/R/dbDataType_Driver_list.R new file mode 100644 index 0000000..5a34cf4 --- /dev/null +++ b/R/dbDataType_Driver_list.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams DBI::dbDataType +#' @usage NULL +dbDataType_KazamDriver_list <- function(dbObj, obj, ...) { + # https://github.com/r-dbi/DBI/issues/70 + callNextMethod(...) +} +#' @rdname DBI +#' @export +setMethod("dbDataType", c("KazamDriver", "list"), dbDataType_KazamDriver_list) diff --git a/R/dbDisconnect_Connection.R b/R/dbDisconnect_Connection.R new file mode 100644 index 0000000..8958019 --- /dev/null +++ b/R/dbDisconnect_Connection.R @@ -0,0 +1,14 @@ +#' @rdname DBI +#' @inheritParams DBI::dbDisconnect +#' @usage NULL +dbDisconnect_KazamConnection <- function(conn, ...) { + if (!dbIsValid(conn)) { + warning("Connection already closed.", call. = FALSE) + } + + # TODO: Free resources + invisible(TRUE) +} +#' @rdname DBI +#' @export +setMethod("dbDisconnect", "KazamConnection", dbDisconnect_KazamConnection) diff --git a/R/dbExistsTable_Connection_character.R b/R/dbExistsTable_Connection_character.R new file mode 100644 index 0000000..0844c06 --- /dev/null +++ b/R/dbExistsTable_Connection_character.R @@ -0,0 +1,19 @@ +#' @rdname DBI +#' @inheritParams DBI::dbExistsTable +#' @usage NULL +dbExistsTable_KazamConnection_character <- function(conn, name, ...) { + name <- dbQuoteIdentifier(conn, name) + + tryCatch( + { + dbGetQuery(conn, paste0("SELECT COUNT(*) FROM ", name, " WHERE 0 = 1")) + TRUE + }, + error = function(e) { + FALSE + } + ) +} +#' @rdname DBI +#' @export +setMethod("dbExistsTable", c("KazamConnection", "character"), dbExistsTable_KazamConnection_character) diff --git a/R/dbFetchArrow_ResultArrow.R b/R/dbFetchArrow_ResultArrow.R new file mode 100644 index 0000000..46054b5 --- /dev/null +++ b/R/dbFetchArrow_ResultArrow.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams DBI::dbFetch +#' @usage NULL +dbFetchArrow_KazamResultArrow <- function(res, ...) { + # TODO: Implement as needed, or remove (default DBI implementation exists) + testthat::skip("Not yet implemented: dbFetchArrow(ResultArrow)") +} +#' @rdname DBI +#' @export +setMethod("dbFetchArrow", "KazamResultArrow", dbFetchArrow_KazamResultArrow) diff --git a/R/dbFetch_Result.R b/R/dbFetch_Result.R new file mode 100644 index 0000000..a3fbbb9 --- /dev/null +++ b/R/dbFetch_Result.R @@ -0,0 +1,18 @@ +#' @rdname DBI +#' @inheritParams DBI::dbFetch +#' @usage NULL +dbFetch_KazamResult <- function(res, n = -1, ...) { + # + # FOR IMPLEMENTERS: + # + # If you are interfacing against a native database library, + # consider copying and adapting Db*.cpp and Db*.h from r-dbi/RPostgres. + # These classes help growing a data frame whose number of rows + # may be unknown at the beginning. + # Similar code is in r-dbi/odbc. + # + testthat::skip("Not yet implemented: dbFetch(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbFetch", "KazamResult", dbFetch_KazamResult) diff --git a/R/dbGetInfo_Connection.R b/R/dbGetInfo_Connection.R new file mode 100644 index 0000000..65c80be --- /dev/null +++ b/R/dbGetInfo_Connection.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbGetInfo +#' @usage NULL +dbGetInfo_KazamConnection <- function(dbObj, ...) { + testthat::skip("Not yet implemented: dbGetInfo(Connection)") +} +#' @rdname DBI +#' @export +setMethod("dbGetInfo", "KazamConnection", dbGetInfo_KazamConnection) diff --git a/R/dbGetInfo_Driver.R b/R/dbGetInfo_Driver.R new file mode 100644 index 0000000..174501b --- /dev/null +++ b/R/dbGetInfo_Driver.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbGetInfo +#' @usage NULL +dbGetInfo_KazamDriver <- function(dbObj, ...) { + testthat::skip("Not yet implemented: dbGetInfo(Driver)") +} +#' @rdname DBI +#' @export +setMethod("dbGetInfo", "KazamDriver", dbGetInfo_KazamDriver) diff --git a/R/dbGetInfo_Result.R b/R/dbGetInfo_Result.R new file mode 100644 index 0000000..35c2321 --- /dev/null +++ b/R/dbGetInfo_Result.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams DBI::dbGetInfo +#' @usage NULL +dbGetInfo_KazamResult <- function(dbObj, ...) { + # Optional + getMethod("dbGetInfo", "DBIResult", asNamespace("DBI"))(dbObj, ...) +} +#' @rdname DBI +#' @export +setMethod("dbGetInfo", "KazamResult", dbGetInfo_KazamResult) diff --git a/R/dbGetRowCount_Result.R b/R/dbGetRowCount_Result.R new file mode 100644 index 0000000..143ed7a --- /dev/null +++ b/R/dbGetRowCount_Result.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbGetRowCount +#' @usage NULL +dbGetRowCount_KazamResult <- function(res, ...) { + testthat::skip("Not yet implemented: dbGetRowCount(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbGetRowCount", "KazamResult", dbGetRowCount_KazamResult) diff --git a/R/dbGetRowsAffected_Result.R b/R/dbGetRowsAffected_Result.R new file mode 100644 index 0000000..28213c8 --- /dev/null +++ b/R/dbGetRowsAffected_Result.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbGetRowsAffected +#' @usage NULL +dbGetRowsAffected_KazamResult <- function(res, ...) { + testthat::skip("Not yet implemented: dbGetRowsAffected(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbGetRowsAffected", "KazamResult", dbGetRowsAffected_KazamResult) diff --git a/R/dbGetStatement_Result.R b/R/dbGetStatement_Result.R new file mode 100644 index 0000000..c7fffd0 --- /dev/null +++ b/R/dbGetStatement_Result.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbGetStatement +#' @usage NULL +dbGetStatement_KazamResult <- function(res, ...) { + testthat::skip("Not yet implemented: dbGetStatement(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbGetStatement", "KazamResult", dbGetStatement_KazamResult) diff --git a/R/dbHasCompleted_Result.R b/R/dbHasCompleted_Result.R new file mode 100644 index 0000000..e374fba --- /dev/null +++ b/R/dbHasCompleted_Result.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbHasCompleted +#' @usage NULL +dbHasCompleted_KazamResult <- function(res, ...) { + testthat::skip("Not yet implemented: dbHasCompleted(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbHasCompleted", "KazamResult", dbHasCompleted_KazamResult) diff --git a/R/dbIsValid_Connection.R b/R/dbIsValid_Connection.R new file mode 100644 index 0000000..aa3924b --- /dev/null +++ b/R/dbIsValid_Connection.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams DBI::dbIsValid +#' @usage NULL +dbIsValid_KazamConnection <- function(dbObj, ...) { + # TODO: Implement + TRUE +} +#' @rdname DBI +#' @export +setMethod("dbIsValid", "KazamConnection", dbIsValid_KazamConnection) diff --git a/R/dbIsValid_Driver.R b/R/dbIsValid_Driver.R new file mode 100644 index 0000000..eef8c8d --- /dev/null +++ b/R/dbIsValid_Driver.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbIsValid +#' @usage NULL +dbIsValid_KazamDriver <- function(dbObj, ...) { + testthat::skip("Not yet implemented: dbIsValid(Driver)") +} +#' @rdname DBI +#' @export +setMethod("dbIsValid", "KazamDriver", dbIsValid_KazamDriver) diff --git a/R/dbIsValid_Result.R b/R/dbIsValid_Result.R new file mode 100644 index 0000000..63e6f37 --- /dev/null +++ b/R/dbIsValid_Result.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbIsValid +#' @usage NULL +dbIsValid_KazamResult <- function(dbObj, ...) { + testthat::skip("Not yet implemented: dbIsValid(Result)") +} +#' @rdname DBI +#' @export +setMethod("dbIsValid", "KazamResult", dbIsValid_KazamResult) diff --git a/R/dbListFields_Connection_character.R b/R/dbListFields_Connection_character.R new file mode 100644 index 0000000..0396e88 --- /dev/null +++ b/R/dbListFields_Connection_character.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbListFields +#' @usage NULL +dbListFields_KazamConnection_character <- function(conn, name, ...) { + testthat::skip("Not yet implemented: dbListFields(Connection, character)") +} +#' @rdname DBI +#' @export +setMethod("dbListFields", c("KazamConnection", "character"), dbListFields_KazamConnection_character) diff --git a/R/dbListTables_Connection.R b/R/dbListTables_Connection.R new file mode 100644 index 0000000..e57e8bb --- /dev/null +++ b/R/dbListTables_Connection.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbListTables +#' @usage NULL +dbListTables_KazamConnection <- function(conn, ...) { + testthat::skip("Not yet implemented: dbListTables(Connection)") +} +#' @rdname DBI +#' @export +setMethod("dbListTables", "KazamConnection", dbListTables_KazamConnection) diff --git a/R/dbQuoteIdentifier_Connection_character.R b/R/dbQuoteIdentifier_Connection_character.R new file mode 100644 index 0000000..91e522c --- /dev/null +++ b/R/dbQuoteIdentifier_Connection_character.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams DBI::dbQuoteIdentifier +#' @usage NULL +dbQuoteIdentifier_KazamConnection_character <- function(conn, x, ...) { + # Optional + getMethod("dbQuoteIdentifier", c("DBIConnection", "character"), asNamespace("DBI"))(conn, x, ...) +} +#' @rdname DBI +#' @export +setMethod("dbQuoteIdentifier", c("KazamConnection", "character"), dbQuoteIdentifier_KazamConnection_character) diff --git a/R/dbQuoteString_Connection_character.R b/R/dbQuoteString_Connection_character.R new file mode 100644 index 0000000..00bf8b7 --- /dev/null +++ b/R/dbQuoteString_Connection_character.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams DBI::dbQuoteString +#' @usage NULL +dbQuoteString_KazamConnection_character <- function(conn, x, ...) { + # Optional + getMethod("dbQuoteString", c("DBIConnection", "character"), asNamespace("DBI"))(conn, x, ...) +} +#' @rdname DBI +#' @export +setMethod("dbQuoteString", c("KazamConnection", "character"), dbQuoteString_KazamConnection_character) diff --git a/R/dbRemoveTable_Connection_character.R b/R/dbRemoveTable_Connection_character.R new file mode 100644 index 0000000..c4a8ea9 --- /dev/null +++ b/R/dbRemoveTable_Connection_character.R @@ -0,0 +1,25 @@ +#' @rdname DBI +#' @param fail_if_missing If `FALSE`, `dbRemoveTable()` succeeds if the +#' table doesn't exist. +#' @inheritParams DBI::dbRemoveTable +#' @usage NULL +dbRemoveTable_KazamConnection_character <- function(conn, name, ..., + temporary = FALSE, + fail_if_missing = TRUE) { + name <- dbQuoteIdentifier(conn, name) + + sql <- paste0( + "DROP ", + if (temporary) "TEMPORARY ", + "TABLE ", + if (!fail_if_missing) "IF EXISTS ", + name + ) + + dbExecute(conn, sql) + + invisible(TRUE) +} +#' @rdname DBI +#' @export +setMethod("dbRemoveTable", c("KazamConnection", "character"), dbRemoveTable_KazamConnection_character) diff --git a/R/dbRollback_Connection.R b/R/dbRollback_Connection.R new file mode 100644 index 0000000..63a7d8a --- /dev/null +++ b/R/dbRollback_Connection.R @@ -0,0 +1,9 @@ +#' @rdname DBI +#' @inheritParams DBI::dbRollback +#' @usage NULL +dbRollback_KazamConnection <- function(conn, ...) { + testthat::skip("Not yet implemented: dbRollback(Connection)") +} +#' @rdname DBI +#' @export +setMethod("dbRollback", "KazamConnection", dbRollback_KazamConnection) diff --git a/R/dbSendQueryArrow_Connection.R b/R/dbSendQueryArrow_Connection.R new file mode 100644 index 0000000..090bf3d --- /dev/null +++ b/R/dbSendQueryArrow_Connection.R @@ -0,0 +1,18 @@ +#' @rdname DBI +#' @inheritParams DBI::dbSendQuery +#' @usage NULL +dbSendQueryArrow_KazamConnection <- function(conn, statement, ..., params = NULL) { + # TODO: Implement as needed, or remove (default DBI implementation exists) + + if (!is.null(params)) { + # TODO: Implement parameter binding + testthat::skip("Not yet implemented: dbSendQueryArrow(params = )") + } + + # TODO: Implement, remove skip() call + testthat::skip("Not yet implemented: dbSendQueryArrow()") + KazamResult(connection = conn, statement = statement) +} +#' @rdname DBI +#' @export +setMethod("dbSendQueryArrow", "KazamConnection", dbSendQueryArrow_KazamConnection) diff --git a/R/dbSendQuery_Connection_character.R b/R/dbSendQuery_Connection_character.R new file mode 100644 index 0000000..44a3abb --- /dev/null +++ b/R/dbSendQuery_Connection_character.R @@ -0,0 +1,16 @@ +#' @rdname DBI +#' @inheritParams DBI::dbSendQuery +#' @usage NULL +dbSendQuery_KazamConnection_character <- function(conn, statement, ..., params = NULL) { + if (!is.null(params)) { + # TODO: Implement parameter binding + testthat::skip("Not yet implemented: dbSendQuery(params = )") + } + + # TODO: Implement, remove skip() call + testthat::skip("Not yet implemented: dbSendQuery()") + KazamResult(connection = conn, statement = statement) +} +#' @rdname DBI +#' @export +setMethod("dbSendQuery", c("KazamConnection", "character"), dbSendQuery_KazamConnection_character) diff --git a/R/dbSendStatement_Connection_character.R b/R/dbSendStatement_Connection_character.R new file mode 100644 index 0000000..5219348 --- /dev/null +++ b/R/dbSendStatement_Connection_character.R @@ -0,0 +1,16 @@ +#' @rdname DBI +#' @inheritParams DBI::dbSendStatement +#' @usage NULL +dbSendStatement_KazamConnection_character <- function(conn, statement, ..., params = NULL) { + if (!is.null(params)) { + # TODO: Implement parameter binding + testthat::skip("Not yet implemented: dbSendStatement(params = )") + } + + # TODO: Implement, remove skip() call + testthat::skip("Not sending statement") + KazamResult(connection = conn, statement = statement) +} +#' @rdname DBI +#' @export +setMethod("dbSendStatement", c("KazamConnection", "character"), dbSendStatement_KazamConnection_character) diff --git a/R/dbWriteTable_Connection_character_data.frame.R b/R/dbWriteTable_Connection_character_data.frame.R new file mode 100644 index 0000000..a80478a --- /dev/null +++ b/R/dbWriteTable_Connection_character_data.frame.R @@ -0,0 +1,82 @@ +#' @rdname DBI +#' @inheritParams DBI::dbWriteTable +#' @param overwrite Allow overwriting the destination table. Cannot be +#' `TRUE` if `append` is also `TRUE`. +#' @param append Allow appending to the destination table. Cannot be +#' `TRUE` if `overwrite` is also `TRUE`. +#' @param field.types character vector of named SQL field types where +#' the names are the names of new table's columns. If missing, types inferred +#' with [DBI::dbDataType()]). +#' @param row.names A logical specifying whether the `row.names` should be +#' output to the output DBMS table; if `TRUE`, an extra field whose name +#' will be whatever the R identifier `"row.names"` maps to the DBMS (see +#' [DBI::make.db.names()]). If `NA` will add rows names if +#' they are characters, otherwise will ignore. +#' @param temporary a logical specifying whether the new table should be +#' temporary. Its default is `FALSE`. +#' @usage NULL +dbWriteTable_KazamConnection_character_data.frame <- function(conn, name, value, overwrite = FALSE, append = FALSE, ..., + field.types = NULL, row.names = NULL, temporary = FALSE) { + # TODO: Implement better ingestion + if (is.null(row.names)) row.names <- FALSE + if ((!is.logical(row.names) && !is.character(row.names)) || length(row.names) != 1L) { + stop("`row.names` must be a logical scalar or a string") + } + if (!is.logical(overwrite) || length(overwrite) != 1L || is.na(overwrite)) { + stop("`overwrite` must be a logical scalar") + } + if (!is.logical(append) || length(append) != 1L || is.na(append)) { + stop("`append` must be a logical scalar") + } + if (!is.logical(temporary) || length(temporary) != 1L) { + stop("`temporary` must be a logical scalar") + } + if (overwrite && append) { + stop("overwrite and append cannot both be TRUE") + } + if (!is.null(field.types) && !(is.character(field.types) && !is.null(names(field.types)) && !anyDuplicated(names(field.types)))) { + stop("`field.types` must be a named character vector with unique names, or NULL") + } + if (append && !is.null(field.types)) { + stop("Cannot specify `field.types` with `append = TRUE`") + } + + if (overwrite) { + tryCatch( + dbRemoveTable(conn, name), + error = function(e) {} + ) + } + + value <- sqlRownamesToColumn(value, row.names) + + if (!append || overwrite) { + if (is.null(field.types)) { + combined_field_types <- lapply(value, dbDataType, dbObj = conn) + } else { + combined_field_types <- rep("", length(value)) + names(combined_field_types) <- names(value) + field_types_idx <- match(names(field.types), names(combined_field_types)) + stopifnot(!any(is.na(field_types_idx))) + combined_field_types[field_types_idx] <- field.types + values_idx <- setdiff(seq_along(value), field_types_idx) + combined_field_types[values_idx] <- lapply(value[values_idx], dbDataType, dbObj = conn) + } + + dbCreateTable( + conn = conn, + name = name, + fields = combined_field_types, + temporary = temporary + ) + } + + if (nrow(value) > 0) { + dbAppendTable(conn, name, value) + } + + invisible(TRUE) +} +#' @rdname DBI +#' @export +setMethod("dbWriteTable", c("KazamConnection", "character", "data.frame"), dbWriteTable_KazamConnection_character_data.frame) diff --git a/R/show_Connection.R b/R/show_Connection.R new file mode 100644 index 0000000..dbf46a2 --- /dev/null +++ b/R/show_Connection.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams methods::show +#' @usage NULL +show_KazamConnection <- function(object) { + cat("\n") + # TODO: Print more details +} +#' @rdname DBI +#' @export +setMethod("show", "KazamConnection", show_KazamConnection) diff --git a/R/show_Driver.R b/R/show_Driver.R new file mode 100644 index 0000000..e7d0034 --- /dev/null +++ b/R/show_Driver.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams methods::show +#' @usage NULL +show_KazamDriver <- function(object) { + cat("\n") + # TODO: Print more details +} +#' @rdname DBI +#' @export +setMethod("show", "KazamDriver", show_KazamDriver) diff --git a/R/show_Result.R b/R/show_Result.R new file mode 100644 index 0000000..8615278 --- /dev/null +++ b/R/show_Result.R @@ -0,0 +1,10 @@ +#' @rdname DBI +#' @inheritParams methods::show +#' @usage NULL +show_KazamResult <- function(object) { + cat("\n") + # TODO: Print more details +} +#' @rdname DBI +#' @export +setMethod("show", "KazamResult", show_KazamResult) diff --git a/README.md b/README.md new file mode 100644 index 0000000..dd4bea6 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# RKazam + + +[![rcc](https://github.com/r-dbi/RKazam/workflows/rcc/badge.svg)](https://github.com/r-dbi/RKazam/actions) +[![Codecov test coverage](https://codecov.io/gh/r-dbi/RKazam/branch/master/graph/badge.svg)](https://codecov.io/gh/r-dbi/RKazam?branch=master) + + +RKazam is an DBI-compliant interface to the hypothetical Kazam database. It is intended to be used as boilerplate for new DBI backends. + +## Installation + +Install from GitHub via + +``` +# install.packages("devtools") +devtools::install_github(c("r-dbi/DBI", "r-dbi/RKazam")) +``` + +--- + +Please note that the 'RKazam' project is released with a +[Contributor Code of Conduct](CODE_OF_CONDUCT.md). +By contributing to this project, you agree to abide by its terms. diff --git a/RKazam.Rproj b/RKazam.Rproj new file mode 100644 index 0000000..5195110 --- /dev/null +++ b/RKazam.Rproj @@ -0,0 +1,22 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 2 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX + +AutoAppendNewline: Yes +StripTrailingWhitespace: Yes + +BuildType: Package +PackageUseDevtools: Yes +PackageInstallArgs: --no-multiarch --with-keep.source --no-byte-compile +PackageCheckArgs: --no-manual +PackageRoxygenize: rd,collate,namespace diff --git a/_pkgdown.yml b/_pkgdown.yml new file mode 100644 index 0000000..fe1a8ba --- /dev/null +++ b/_pkgdown.yml @@ -0,0 +1,32 @@ +url: https://rkazam.r-dbi.org + +template: + package: dbitemplate + +home: + links: + - text: Report a security vulnerability + href: https://dbi.r-dbi.org/security.html + - text: DBI project website + href: https://r-dbi.org + +reference: +- title: DBI methods + desc: Implementations for generics defined in the DBI package. + contents: + - DBI + +- title: Package documentation + contents: + - Kazam + - RKazam-package + +development: + mode: auto + +authors: + Kirill Müller: + href: https://krlmlr.info + +news: + cran_dates: false diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..04c5585 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,14 @@ +comment: false + +coverage: + status: + project: + default: + target: auto + threshold: 1% + informational: true + patch: + default: + target: auto + threshold: 1% + informational: true diff --git a/man/DBI.Rd b/man/DBI.Rd new file mode 100644 index 0000000..cd099a1 --- /dev/null +++ b/man/DBI.Rd @@ -0,0 +1,261 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Driver.R, R/Connection.R, R/Result.R, +% R/ResultArrow.R, R/dbAppendTable_Connection_character_data.frame.R, +% R/dbBegin_Connection.R, R/dbBind_Result.R, R/dbClearResult_Result.R, +% R/dbClearResult_ResultArrow.R, R/dbColumnInfo_Result.R, +% R/dbCommit_Connection.R, R/dbConnect_Driver.R, R/dbDataType_Connection.R, +% R/dbDataType_Driver.R, R/dbDataType_Driver_list.R, +% R/dbDisconnect_Connection.R, R/dbExistsTable_Connection_character.R, +% R/dbFetchArrow_ResultArrow.R, R/dbFetch_Result.R, R/dbGetInfo_Connection.R, +% R/dbGetInfo_Driver.R, R/dbGetInfo_Result.R, R/dbGetRowCount_Result.R, +% R/dbGetRowsAffected_Result.R, R/dbGetStatement_Result.R, +% R/dbHasCompleted_Result.R, R/dbIsValid_Connection.R, R/dbIsValid_Driver.R, +% R/dbIsValid_Result.R, R/dbListFields_Connection_character.R, +% R/dbListTables_Connection.R, R/dbQuoteIdentifier_Connection_character.R, +% R/dbQuoteString_Connection_character.R, +% R/dbRemoveTable_Connection_character.R, R/dbRollback_Connection.R, +% R/dbSendQueryArrow_Connection.R, R/dbSendQuery_Connection_character.R, +% R/dbSendStatement_Connection_character.R, +% R/dbWriteTable_Connection_character_data.frame.R, R/show_Connection.R, +% R/show_Driver.R, R/show_Result.R +\docType{class} +\name{DBI} +\alias{DBI} +\alias{KazamDriver-class} +\alias{KazamConnection-class} +\alias{KazamResult-class} +\alias{KazamResultArrow-class} +\alias{dbAppendTable_KazamConnection} +\alias{dbAppendTable,KazamConnection-method} +\alias{dbBegin_KazamConnection} +\alias{dbBegin,KazamConnection-method} +\alias{dbBind_KazamResult} +\alias{dbBind,KazamResult-method} +\alias{dbClearResult_KazamResult} +\alias{dbClearResult,KazamResult-method} +\alias{dbClearResult_KazamResultArrow} +\alias{dbClearResult,KazamResultArrow-method} +\alias{dbColumnInfo_KazamResult} +\alias{dbColumnInfo,KazamResult-method} +\alias{dbCommit_KazamConnection} +\alias{dbCommit,KazamConnection-method} +\alias{dbConnect_KazamDriver} +\alias{dbConnect,KazamDriver-method} +\alias{dbDataType_KazamConnection} +\alias{dbDataType,KazamConnection,ANY-method} +\alias{dbDataType_KazamDriver} +\alias{dbDataType,KazamDriver,ANY-method} +\alias{dbDataType_KazamDriver_list} +\alias{dbDataType,KazamDriver,list-method} +\alias{dbDisconnect_KazamConnection} +\alias{dbDisconnect,KazamConnection-method} +\alias{dbExistsTable_KazamConnection_character} +\alias{dbExistsTable,KazamConnection,character-method} +\alias{dbFetchArrow_KazamResultArrow} +\alias{dbFetchArrow,KazamResultArrow-method} +\alias{dbFetch_KazamResult} +\alias{dbFetch,KazamResult-method} +\alias{dbGetInfo_KazamConnection} +\alias{dbGetInfo,KazamConnection-method} +\alias{dbGetInfo_KazamDriver} +\alias{dbGetInfo,KazamDriver-method} +\alias{dbGetInfo_KazamResult} +\alias{dbGetInfo,KazamResult-method} +\alias{dbGetRowCount_KazamResult} +\alias{dbGetRowCount,KazamResult-method} +\alias{dbGetRowsAffected_KazamResult} +\alias{dbGetRowsAffected,KazamResult-method} +\alias{dbGetStatement_KazamResult} +\alias{dbGetStatement,KazamResult-method} +\alias{dbHasCompleted_KazamResult} +\alias{dbHasCompleted,KazamResult-method} +\alias{dbIsValid_KazamConnection} +\alias{dbIsValid,KazamConnection-method} +\alias{dbIsValid_KazamDriver} +\alias{dbIsValid,KazamDriver-method} +\alias{dbIsValid_KazamResult} +\alias{dbIsValid,KazamResult-method} +\alias{dbListFields_KazamConnection_character} +\alias{dbListFields,KazamConnection,character-method} +\alias{dbListTables_KazamConnection} +\alias{dbListTables,KazamConnection-method} +\alias{dbQuoteIdentifier_KazamConnection_character} +\alias{dbQuoteIdentifier,KazamConnection,character-method} +\alias{dbQuoteString_KazamConnection_character} +\alias{dbQuoteString,KazamConnection,character-method} +\alias{dbRemoveTable_KazamConnection_character} +\alias{dbRemoveTable,KazamConnection,character-method} +\alias{dbRollback_KazamConnection} +\alias{dbRollback,KazamConnection-method} +\alias{dbSendQueryArrow_KazamConnection} +\alias{dbSendQueryArrow,KazamConnection-method} +\alias{dbSendQuery_KazamConnection_character} +\alias{dbSendQuery,KazamConnection,character-method} +\alias{dbSendStatement_KazamConnection_character} +\alias{dbSendStatement,KazamConnection,character-method} +\alias{dbWriteTable_KazamConnection_character_data.frame} +\alias{dbWriteTable,KazamConnection,character,data.frame-method} +\alias{show_KazamConnection} +\alias{show,KazamConnection-method} +\alias{show_KazamDriver} +\alias{show,KazamDriver-method} +\alias{show_KazamResult} +\alias{show,KazamResult-method} +\title{DBI methods} +\usage{ +\S4method{dbAppendTable}{KazamConnection}(conn, name, value, ..., row.names = NULL) + +\S4method{dbBegin}{KazamConnection}(conn, ...) + +\S4method{dbBind}{KazamResult}(res, params, ...) + +\S4method{dbClearResult}{KazamResult}(res, ...) + +\S4method{dbClearResult}{KazamResultArrow}(res, ...) + +\S4method{dbColumnInfo}{KazamResult}(res, ...) + +\S4method{dbCommit}{KazamConnection}(conn, ...) + +\S4method{dbConnect}{KazamDriver}(drv, ...) + +\S4method{dbDataType}{KazamConnection,ANY}(dbObj, obj, ...) + +\S4method{dbDataType}{KazamDriver,ANY}(dbObj, obj, ...) + +\S4method{dbDataType}{KazamDriver,list}(dbObj, obj, ...) + +\S4method{dbDisconnect}{KazamConnection}(conn, ...) + +\S4method{dbExistsTable}{KazamConnection,character}(conn, name, ...) + +\S4method{dbFetchArrow}{KazamResultArrow}(res, ...) + +\S4method{dbFetch}{KazamResult}(res, n = -1, ...) + +\S4method{dbGetInfo}{KazamConnection}(dbObj, ...) + +\S4method{dbGetInfo}{KazamDriver}(dbObj, ...) + +\S4method{dbGetInfo}{KazamResult}(dbObj, ...) + +\S4method{dbGetRowCount}{KazamResult}(res, ...) + +\S4method{dbGetRowsAffected}{KazamResult}(res, ...) + +\S4method{dbGetStatement}{KazamResult}(res, ...) + +\S4method{dbHasCompleted}{KazamResult}(res, ...) + +\S4method{dbIsValid}{KazamConnection}(dbObj, ...) + +\S4method{dbIsValid}{KazamDriver}(dbObj, ...) + +\S4method{dbIsValid}{KazamResult}(dbObj, ...) + +\S4method{dbListFields}{KazamConnection,character}(conn, name, ...) + +\S4method{dbListTables}{KazamConnection}(conn, ...) + +\S4method{dbQuoteIdentifier}{KazamConnection,character}(conn, x, ...) + +\S4method{dbQuoteString}{KazamConnection,character}(conn, x, ...) + +\S4method{dbRemoveTable}{KazamConnection,character}(conn, name, ..., temporary = FALSE, fail_if_missing = TRUE) + +\S4method{dbRollback}{KazamConnection}(conn, ...) + +\S4method{dbSendQueryArrow}{KazamConnection}(conn, statement, ..., params = NULL) + +\S4method{dbSendQuery}{KazamConnection,character}(conn, statement, ..., params = NULL) + +\S4method{dbSendStatement}{KazamConnection,character}(conn, statement, ..., params = NULL) + +\S4method{dbWriteTable}{KazamConnection,character,data.frame}( + conn, + name, + value, + overwrite = FALSE, + append = FALSE, + ..., + field.types = NULL, + row.names = NULL, + temporary = FALSE +) + +\S4method{show}{KazamConnection}(object) + +\S4method{show}{KazamDriver}(object) + +\S4method{show}{KazamResult}(object) +} +\arguments{ +\item{conn}{A \linkS4class{DBIConnection} object, as returned by +\code{\link[DBI:dbConnect]{dbConnect()}}.} + +\item{name}{The table name, passed on to \code{\link[DBI:dbQuoteIdentifier]{dbQuoteIdentifier()}}. Options are: +\itemize{ +\item a character string with the unquoted DBMS table name, +e.g. \code{"table_name"}, +\item a call to \code{\link[DBI:Id]{Id()}} with components to the fully qualified table name, +e.g. \code{Id(schema = "my_schema", table = "table_name")} +\item a call to \code{\link[DBI:SQL]{SQL()}} with the quoted and fully qualified table name +given verbatim, e.g. \code{SQL('"my_schema"."table_name"')} +}} + +\item{value}{A \link{data.frame} (or coercible to data.frame).} + +\item{...}{Other parameters passed on to methods.} + +\item{row.names}{A logical specifying whether the \code{row.names} should be +output to the output DBMS table; if \code{TRUE}, an extra field whose name +will be whatever the R identifier \code{"row.names"} maps to the DBMS (see +\code{\link[DBI:make.db.names]{DBI::make.db.names()}}). If \code{NA} will add rows names if +they are characters, otherwise will ignore.} + +\item{res}{An object inheriting from \linkS4class{DBIResult}.} + +\item{params}{For \code{dbBind()}, a list of values, named or unnamed, +or a data frame, with one element/column per query parameter. +For \code{dbBindArrow()}, values as a nanoarrow stream, +with one column per query parameter.} + +\item{drv}{an object that inherits from \linkS4class{DBIDriver}, +or an existing \linkS4class{DBIConnection} +object (in order to clone an existing connection).} + +\item{dbObj}{A object inheriting from \linkS4class{DBIDriver} +or \linkS4class{DBIConnection}} + +\item{obj}{An R object whose SQL type we want to determine.} + +\item{n}{maximum number of records to retrieve per fetch. Use \code{n = -1} +or \code{n = Inf} +to retrieve all pending records. Some implementations may recognize other +special values.} + +\item{x}{A character vector, \link[DBI]{SQL} or \link[DBI]{Id} object to quote as identifier.} + +\item{temporary}{a logical specifying whether the new table should be +temporary. Its default is \code{FALSE}.} + +\item{fail_if_missing}{If \code{FALSE}, \code{dbRemoveTable()} succeeds if the +table doesn't exist.} + +\item{statement}{a character string containing SQL.} + +\item{overwrite}{Allow overwriting the destination table. Cannot be +\code{TRUE} if \code{append} is also \code{TRUE}.} + +\item{append}{Allow appending to the destination table. Cannot be +\code{TRUE} if \code{overwrite} is also \code{TRUE}.} + +\item{field.types}{character vector of named SQL field types where +the names are the names of new table's columns. If missing, types inferred +with \code{\link[DBI:dbDataType]{DBI::dbDataType()}}).} + +\item{object}{Any R object} +} +\description{ +Implementations of pure virtual functions defined in the \code{DBI} package. +} diff --git a/man/Kazam.Rd b/man/Kazam.Rd new file mode 100644 index 0000000..5b8f8b2 --- /dev/null +++ b/man/Kazam.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Driver.R +\name{Kazam} +\alias{Kazam} +\title{Kazam driver} +\usage{ +Kazam() +} +\description{ +TBD. +} +\examples{ +\dontrun{ +#' library(DBI) +RKazam::Kazam() +} +} diff --git a/man/RKazam-package.Rd b/man/RKazam-package.Rd new file mode 100644 index 0000000..b180689 --- /dev/null +++ b/man/RKazam-package.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RKazam-package.R +\docType{package} +\name{RKazam-package} +\alias{RKazam} +\alias{RKazam-package} +\title{RKazam: Boilerplate for implementing a DBI back end} +\description{ +A dummy DBI back end that provides access to a hypothetical data source named "Kazam", intended to be used as boilerplate for implementing DBI back ends from scratch. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://rkazam.r-dbi.org} + \item \url{https://github.com/r-dbi/RKazam} +} + +} +\author{ +\strong{Maintainer}: Kirill Müller \email{kirill@cynkra.com} (\href{https://orcid.org/0000-0002-1416-3412}{ORCID}) + +Other contributors: +\itemize{ + \item R Consortium [funder] +} + +} +\keyword{internal} diff --git a/man/reexports.Rd b/man/reexports.Rd new file mode 100644 index 0000000..67cd2cb --- /dev/null +++ b/man/reexports.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Driver.R, R/Connection.R +\docType{import} +\name{reexports} +\alias{reexports} +\alias{dbCanConnect} +\alias{Id} +\alias{dbIsReadOnly} +\alias{dbQuoteLiteral} +\alias{dbUnquoteIdentifier} +\alias{dbGetQuery} +\alias{dbExecute} +\alias{dbReadTable} +\alias{dbCreateTable} +\alias{dbAppendTable} +\alias{dbListObjects} +\alias{dbWithTransaction} +\title{Objects exported from other packages} +\keyword{internal} +\description{ +These objects are imported from other packages. Follow the links +below to see their documentation. + +\describe{ + \item{DBI}{\code{\link[DBI]{dbAppendTable}}, \code{\link[DBI]{dbCanConnect}}, \code{\link[DBI]{dbCreateTable}}, \code{\link[DBI]{dbExecute}}, \code{\link[DBI]{dbGetQuery}}, \code{\link[DBI]{dbIsReadOnly}}, \code{\link[DBI]{dbListObjects}}, \code{\link[DBI]{dbQuoteLiteral}}, \code{\link[DBI]{dbReadTable}}, \code{\link[DBI]{dbUnquoteIdentifier}}, \code{\link[DBI]{dbWithTransaction}}, \code{\link[DBI]{Id}}} +}} + diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..8483400 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,3 @@ +library("testthat") + +test_check("RKazam") diff --git a/tests/testthat/helper-DBItest.R b/tests/testthat/helper-DBItest.R new file mode 100644 index 0000000..b191ef9 --- /dev/null +++ b/tests/testthat/helper-DBItest.R @@ -0,0 +1,22 @@ +if (requireNamespace("DBItest", quietly = TRUE)) DBItest::make_context( + Kazam(), + list(), + tweaks = suppressWarnings(DBItest::tweaks( + dbitest_version = "1.7.3" + )), + name = "RKazam", + default_skip = c( + # TODO: Remove when dbDisconnect() is implemented + "can_disconnect", + "disconnect_closed_connection", + "disconnect_invalid_connection", + # TODO: Remove when dbIsValid() is implemented + "is_valid_connection", + "is_valid_stale_connection", + # TODO: Understand why test fails in R < 3.6 + if (getRversion() < "3.6") "connect_format", + # Fails with older DBItest + if (packageVersion("DBItest") < "1.7.2") "reexport", + NULL + ) +) diff --git a/tests/testthat/test-DBItest.R b/tests/testthat/test-DBItest.R new file mode 100644 index 0000000..3c83b5f --- /dev/null +++ b/tests/testthat/test-DBItest.R @@ -0,0 +1,3 @@ +if (requireNamespace("DBItest", quietly = TRUE) && identical(Sys.getenv("NOT_CRAN"), "true") && packageVersion("DBItest") >= "1.7.2") { + DBItest::test_all() +}