Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add get sql function #68

Merged
merged 23 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3a142cf
fix typo in contributing guide
cjrace Feb 27, 2024
fa575a3
start to add get_clean_sql and tests (WIP)
cjrace Feb 27, 2024
1bde4a3
add code cov details to contributing file
cjrace Feb 27, 2024
27d73f5
Add link to reference documentation in the examples section
cjrace Feb 27, 2024
af9a49c
commit current progress adding unit tests (WIP)
cjrace Feb 28, 2024
57f892c
fix typo in contributing guide
cjrace Feb 27, 2024
272bcad
start to add get_clean_sql and tests (WIP)
cjrace Feb 27, 2024
47fee51
add code cov details to contributing file
cjrace Feb 27, 2024
5a2b219
Add link to reference documentation in the examples section
cjrace Feb 27, 2024
75aea11
commit current progress adding unit tests (WIP)
cjrace Feb 28, 2024
140d4ae
Merge branch 'add-get_sql' of https://github.com/dfe-analytical-servi…
cjrace Mar 7, 2024
6c5cf74
fix tests for sql function
cjrace Mar 8, 2024
23b2db1
add roxygen2 examples to contributing file
cjrace Mar 8, 2024
d945bfa
add connecting to sql vignette
cjrace Mar 9, 2024
7237558
update get clean sql, contributing and reference documentation
cjrace Mar 9, 2024
7e6bb47
Increment version number to 0.2.0
cjrace Mar 9, 2024
31441c6
tidy package following lintr advice
cjrace Mar 9, 2024
e39ea6a
remove capitalised extension test (causes test errors on linux)
cjrace Mar 9, 2024
eafd155
add Jen as a contributor to the package
cjrace Mar 11, 2024
0b1c56a
Initial response to PR comments (more to complete on troubleshooting)
cjrace Mar 12, 2024
ef627e2
fix lint issues
cjrace Mar 12, 2024
6d07780
update connecting to sql vignette to specific select style queries only
cjrace Mar 23, 2024
a7ece2f
update wordlist and rebuild package docs
cjrace Mar 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 48 additions & 12 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ install.packages("lintr")
install.packages("styler")
```

Where possible, we'd recommend following the [Test Driven Development (TDD)](https://testdriven.io/test-driven-development/) approach:
Where possible, we'd recommend following the [Test Driven Development (TDD)](https://testdriven.io/test-driven-development/) approach. Though if you're new to package development, or already have code for a specific function feel free to start with step 2, to copy the function into the package and then go back to step 1 afterwards.

1. Write tests for the behaviour you want. Either edit an existing test script, or if adding a new function, create a test script using:
1. Write tests using [testthat](https://r-pkgs.org/testing-basics.html) for the behaviour you want. Either edit an existing test script, or if adding a new function, create a test script using:

``` r
usethis::usetest("name_of_new_function")
usethis::use_test("name_of_new_function")
```

2. Write just enough code so that the tests pass. Again, either edit an existing function, or add a new R script using:
Expand All @@ -56,38 +56,54 @@ usethis::usetest("name_of_new_function")
usethis::use_r("name_of_new_function")
```

3. Add documentation for what you've done. Follow the [roxygen2](https://roxygen2.r-lib.org/articles/rd.html) pattern for comments.
3. Add documentation for what you've done. Follow the [roxygen2](https://roxygen2.r-lib.org/articles/rd.html) pattern for comments. Here's an example of what it looks like for a basic `add()` function:

```
#' @description Add together two numbers
#'
#' @param x A number.
#' @param y A number.
#' @return A number.
#' @examples
#' add(1, 1)
#' add(10, 1)
add <- function(x, y) {
x + y
}
```

4. Continue to improve code while keeping tests passing. You can automatically style code using:

``` r
styler::style_pkg()
```

5. Run a full check of the package. Here's a few ways you can do this:
5. Run a full check of the package using the following functions:

``` r
devtools::check() # General package check, can also use Ctrl-Shift-E
lintr::lint_pkg() # Check styling of code
lintr::lint_package() # Check formatting of code
spelling::spell_check() # Check for spelling mistakes
```

## Handy workflows

Keyboard shortcuts for the `devtools` package to use while in RStudio:

* `load_all()` (Ctrl-Shift-L): Load code with dfeR package
* `test()` (Ctrl-Shift-T): Run tests
* `document()` (Ctrl-Shift-D): Rebuild docs and NAMESPACE
* `check()` (Ctrl-Shift-E): Check complete package
``` r
load_all() # (Ctrl-Shift-L): Load code with dfeR package
test() # (Ctrl-Shift-T): Run tests
document() # (Ctrl-Shift-D): Rebuild docs and NAMESPACE
check() # (Ctrl-Shift-E): Check complete package
```

We recommend using the [usethis](https://usethis.r-lib.org/index.html) package where possible for consistency and simplicity.

## Adding package dependencies

Add any packages the package users will need with:
``` r
usethis::use_package(pkgname, type = "imports")
usethis::use_package(pkgname)
```

Add any packages that package developers only may need with:
Expand Down Expand Up @@ -159,7 +175,19 @@ lintr::lint_package()

### Testing

We use [testthat](https://cran.r-project.org/package=testthat) for unit tests, we expect all new functions to have some level of test coverage.
We use [testthat](https://cran.r-project.org/package=testthat) for unit tests, we expect all new functions to have some level of test coverage.

If you want to see examples of existing tests for inspiration, take a look inside the `tests/testthat/` folder.

### Test coverage

There are GitHub Actions workflows that check and link the package to [codecov.io](https://app.codecov.io/gh/dfe-analytical-services/), this runs automatic scans to check the % of lines in functions that we are testing. On the [dfeR codecov pages](https://app.codecov.io/gh/dfe-analytical-services/dfeR) you can preview the variation by branch and commit to see the impact of changes made.

You will need to create an account or login using GitHub to see the pages.

The current % of coverage is shown as a badge on the package [README on GitHub](https://github.com/dfe-analytical-services/dfeR).

It is worth noting that 100% coverage does not mean that the tests are perfect, it only means that all lines are ran in tests, so it's more a measure of quantity rather than quality. Interesting to see all the same though, and we'd recommend using it to spot any potential elements of more complicated functions that you may have forgotten to test.

### Spelling

Expand All @@ -179,6 +207,14 @@ To automatically pick up genuine new words in the package and add to this list,
spelling::update_wordlist()
```

## Adding vignettes

Vignettes can be found in the `vignettes/` folder as .Rmd files. To start a new one use:

``` r
usethis::use_vignette("name_of_vignette")
```

## Code of Conduct

Please note that the dfeR 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.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
.httr-oauth
.DS_Store
docs
inst/doc
11 changes: 9 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
Type: Package
Package: dfeR
Title: Common DfE R tasks
Version: 0.1.1
Version: 0.2.0
Authors@R: c(
person("Cam", "Race", , "[email protected]", role = c("aut", "cre")),
person("Laura", "Selby", , "[email protected]", role = "aut"),
rmbielby marked this conversation as resolved.
Show resolved Hide resolved
person("Adam", "Robinson", role = "aut")
person("Adam", "Robinson", role = "aut"),
person("Jen", "Machin", , "[email protected]", role = "ctb"),
person("Rich", "Bielby", , "[email protected]", role = "ctb",
comment = c(ORCID = "0000-0001-9070-9969"))
)
Description: This package contains R functions to allow DfE analysts to
re-use code for common analytical tasks that are undertaken across the
Expand All @@ -17,8 +20,12 @@ BugReports: https://github.com/dfe-analytical-services/dfeR/issues
Imports:
lifecycle
Suggests:
knitr,
rmarkdown,
spelling,
testthat (>= 3.0.0)
VignetteBuilder:
knitr
Config/testthat/edition: 3
Encoding: UTF-8
Language: en-GB
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export(format_ay)
export(format_ay_reverse)
export(format_fy)
export(format_fy_reverse)
export(get_clean_sql)
export(round_five_up)
importFrom(lifecycle,deprecated)
15 changes: 15 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# dfeR 0.2.0

Add function for formatting financial years:

- format_fy()

Add reversing functions for academic and financial years:

- format_ay_reverse()
- format_fy_reverse()

Add function for grabbing and cleaning a SQL script, and vignette for connecting to SQL.

- get_clean_sql()

# dfeR 0.1.1

Add default value to decimal place argument of round_five_up() function.
Expand Down
66 changes: 66 additions & 0 deletions R/get_clean_sql.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#' Get a cleaned SQL script into R
#'
#' @description
#' This function cleans a SQL script, ready for using within R in the DfE.
#'
#' @param filepath path to a SQL script
#' @param additional_settings TRUE or FALSE boolean for the addition of
#' settings at the start of the SQL script
#' @return Cleaned string containing SQL query
#' @export
#' @examples
#' # This assumes you have already set up a database connection
#' # and that the filepath for the function exists
#' # For more details see the vignette on connecting to SQL
#'
#' # Pull a cleaned version of the SQL file into R
#' if (file.exists("your_script.sql")) {
#' sql_query <- get_clean_sql("your_script.sql")
#' }
get_clean_sql <- function(filepath, additional_settings = FALSE) {
if (!additional_settings %in% c(TRUE, FALSE)) {
stop(
"additional_settings must be either TRUE or FALSE"
)
}

# check filepath leads to a SQL file
if (tolower(tools::file_ext(filepath)) != "sql") {
stop("filepath must point to a SQL script, with a .sql extension")
}

# The file() function will error if the file can't be found
# Open a connection to the file
con <- file(filepath, "r")
sql_string <- ""

while (TRUE) {
line <- readLines(con, n = 1)

if (length(line) == 0) {
break
}

line <- gsub("\\t", " ", line)
line <- gsub("\\n", " ", line)

if (grepl("--", line) == TRUE) {
line <- paste(sub("--", "/*", line), "*/")
}

sql_string <- paste(sql_string, line)
}

# Close connection to the file
close(con)

if (additional_settings == TRUE) {
# Prefix with settings that sometimes help
sql_string <- paste(
"SET ANSI_PADDING OFF",
"SET NOCOUNT ON;"
)
}

return(sql_string)
}
2 changes: 2 additions & 0 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,5 @@ This is a basic example showing the `format_ay()` function:
library(dfeR)
format_ay(202425)
```

For more details on all the functions available in this package, and examples of how to use them, please see our [dfeR package reference documentation](https://dfe-analytical-services.github.io/dfeR/reference/index.html).
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,7 @@ library(dfeR)
format_ay(202425)
#> [1] "2024/25"
```

For more details on all the functions available in this package, and
examples of how to use them, please see our [dfeR package reference
documentation](https://dfe-analytical-services.github.io/dfeR/reference/index.html).
13 changes: 13 additions & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,16 @@ template:
bslib:
pkgdown-nav-height: 81.4468px
code-color: "ffffff"

reference:
- title: Helper functions
contents:
- round_five_up

- title: Formatting
contents:
- starts_with("format_")

- title: Database connections
contents:
- get_clean_sql
9 changes: 6 additions & 3 deletions inst/WORDLIST
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ CMD
Codecov
DfE
Lifecycle
ORCID
SSMS
ay
ch
dbplyr
dfeshiny
ethz
fy
lauraselby
odbc
pkgdown
renv
stat
sql
6 changes: 6 additions & 0 deletions man/dfeR-package.Rd

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

30 changes: 30 additions & 0 deletions man/get_clean_sql.Rd

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

3 changes: 3 additions & 0 deletions tests/sql_scripts/simple.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Simple SQL script to get all data from my database table

SELECT * FROM [my_database_table]
54 changes: 54 additions & 0 deletions tests/testthat/test-get_clean_sql.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
test_that("Can retrieve basic script", {
expect_equal(
get_clean_sql("../sql_scripts/simple.sql"),
paste0(
" /* Simple SQL script to get all data from my database table",
" */ SELECT * FROM [my_database_table]"
)
)
})

test_that("Adds additional settings", {
# Check that the output starts with the desired lines
expect_true(
grepl(
"^SET ANSI_PADDING OFF SET NOCOUNT ON;",
get_clean_sql("../sql_scripts/simple.sql", additional_settings = TRUE)
)
)
})

test_that("Doesn't add additional settings", {
# Check that the output doesn't start with the additional lines
expect_false(
grepl(
"^SET ANSI_PADDING OFF SET NOCOUNT ON;",
get_clean_sql("../sql_scripts/simple.sql", additional_settings = FALSE)
)
)
# Check that the output doesn't start with the additional lines
expect_false(
grepl(
"^SET ANSI_PADDING OFF SET NOCOUNT ON;",
get_clean_sql("../sql_scripts/simple.sql")
)
)
})

test_that("Rejects non-boolean values for additional_settings", {
expect_error(
get_clean_sql("../sql_scripts/simple.sql", additional_settings = "True"),
"additional_settings must be either TRUE or FALSE"
)
expect_error(
get_clean_sql("../sql_scripts/simple.sql", additional_settings = ""),
"additional_settings must be either TRUE or FALSE"
)
})

test_that("Rejects file that don't have SQL extension", {
expect_error(
get_clean_sql("../spelling.R"),
""
)
})
2 changes: 2 additions & 0 deletions vignettes/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.html
*.R
Loading