Skip to content

Commit

Permalink
Replace remote MySQL database with local SQLite database (#192)
Browse files Browse the repository at this point in the history
  • Loading branch information
hadley authored Oct 3, 2024
1 parent 8cc6b70 commit f3b0cfa
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 122 deletions.
3 changes: 1 addition & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ Suggests:
dplyr,
knitr,
rmarkdown,
RMySQL,
RSQLite,
shiny,
testthat (>= 3.0.0),
tibble
VignetteBuilder:
VignetteBuilder:
knitr
Config/Needs/website: tidyverse/tidytemplate
Config/testthat/edition: 3
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export(Pool)
export(dbBreak)
export(dbPool)
export(demoDb)
export(localCheckout)
export(onActivate)
export(onDestroy)
Expand Down
14 changes: 8 additions & 6 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# pool (development version)

* Switched from hosted MySQL database to local SQLite database.

# pool 1.0.3

* Now explicitly requires DBI 1.2.0 (#178) and messages if you're using an
* Now explicitly requires DBI 1.2.0 (#178) and messages if you're using an
old dbplyr (#179).

# pool 1.0.2

* No longer depends on the withr package, by instead requiring R 3.6.

* Add wrappers for dbplyr generics `db_col_types()` (#171) and
* Add wrappers for dbplyr generics `db_col_types()` (#171) and
`db_copy_to()` (#172).

* Pool no longer generates spurious messages about needing to use
* Pool no longer generates spurious messages about needing to use
`in_schema()` or avoiding the use of `ident_q()`.

* Add support for new DBI generics that return Arrow objects.
Expand All @@ -21,7 +23,7 @@

* `copy_to()` now returns a tbl that uses the Pool.

* Added missing methods for `sql_join_suffix()` (#165) and
* Added missing methods for `sql_join_suffix()` (#165) and
`sql_query_explain()` (#167).

# pool 1.0.0
Expand All @@ -44,7 +46,7 @@
* pool now implements the dbplyr 2.0.0 interface, eliminating warnings when
using pool with dplyr (#132).

* Pool errors and warnings have been reviewed with an eye to making them
* Pool errors and warnings have been reviewed with an eye to making them
more immediately actionable (#145).

* Objects are now validated once on first checkout to ensure that the
Expand All @@ -58,7 +60,7 @@

* `dbPool()`'s `validateQuery` is now actually used (#153).

* DBI methods should dispatch correctly in more cases; in particular
* DBI methods should dispatch correctly in more cases; in particular
`dbReadTable()` and friends will now work correctly when used with
`DBI::Id()` (#120).

Expand Down
18 changes: 1 addition & 17 deletions R/DBI.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,13 @@
#' @export
#' @examples
#' # You use a dbPool in the same way as a standard DBI connection
#' pool <- dbPool(RSQLite::SQLite())
#' pool <- dbPool(RSQLite::SQLite(), dbname = demoDb())
#' pool
#'
#' DBI::dbWriteTable(pool, "mtcars", mtcars)
#' dbGetQuery(pool, "SELECT * FROM mtcars LIMIT 4")
#'
#' # Always close a pool when you're done using it
#' poolClose(pool)
#'
#' # Using the RMySQL package
#' if (requireNamespace("RMySQL", quietly = TRUE)) {
#' pool <- dbPool(
#' drv = RMySQL::MySQL(),
#' dbname = "shinydemo",
#' host = "shiny-demo.csa7qlmguqrf.us-east-1.rds.amazonaws.com",
#' username = "guest",
#' password = "guest"
#' )
#'
#' dbGetQuery(pool, "SELECT * from City LIMIT 5;")
#'
#' poolClose(pool)
#' }
dbPool <- function(drv,
...,
minSize = 1,
Expand Down
24 changes: 24 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,27 @@ defer <- function(expr, envir = parent.frame(), after = FALSE) {
thunk <- as.call(list(function() expr))
do.call(on.exit, list(thunk, TRUE, after), envir = envir)
}

#' Create a demo SQLite database
#'
#' This function creates a temporary SQLite database for demonstration purposes.
#' It populates the database with two tables: 'mtcars' and 'faithful'.
#'
#' @export
#' @keywords internal
demoDb <- function() {
check_installed("RSQLite")

path <- file.path(tools::R_user_dir("pool", "cache"), "demo.sqlite3")
dir.create(dirname(path), showWarnings = FALSE, recursive = TRUE)

if (!file.exists(path)) {
con <- DBI::dbConnect(RSQLite::SQLite(), path)
on.exit(DBI::dbDisconnect(con))

DBI::dbWriteTable(con, "mtcars", datasets::mtcars, row.names = "model")
DBI::dbWriteTable(con, "faithful", datasets::faithful)
}

path
}
22 changes: 8 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,35 @@ Learn more about why pool is needed in `vignette("why-pool")`.

## Usage

Here’s a simple example of using a pool within a Shiny app (feel free to try it yourself):
Here’s a simple example of using a pool within a Shiny app:

```r
library(shiny)
library(dplyr)
library(pool)
loadNamespace("dbplyr")

pool <- dbPool(
drv = RMySQL::MySQL(),
dbname = "shinydemo",
host = "shiny-demo.csa7qlmguqrf.us-east-1.rds.amazonaws.com",
username = "guest",
password = "guest"
)
pool <- dbPool(RSQLite::SQLite(), dbname = demoDb())
onStop(function() {
poolClose(pool)
})

ui <- fluidPage(
textInput("ID", "Enter your ID:", "5"),
textInput("cyl", "Enter your number of cylinders:", "4"),
tableOutput("tbl"),
numericInput("nrows", "How many cities to show?", 10),
numericInput("nrows", "How many cars to show?", 10),
plotOutput("popPlot")
)

server <- function(input, output, session) {
city <- tbl(pool, "City")
cars <- tbl(pool, "mtcars")

output$tbl <- renderTable({
city |> filter(ID == !!input$ID) |> collect()
cars %>% filter(cyl == !!input$cyl) %>% collect()
})
output$popPlot <- renderPlot({
df <- city |> head(input$nrows) |> collect()
pop <- df |> pull("Population", name = "Name")
df <- cars %>% head(input$nrows) %>% collect()
pop <- df %>% pull("mpg", name = "model")
barplot(pop)
})
}
Expand Down
18 changes: 1 addition & 17 deletions man/dbPool.Rd

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

13 changes: 13 additions & 0 deletions man/demoDb.Rd

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

2 changes: 2 additions & 0 deletions vignettes/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
*.html
*.R

/.quarto/
21 changes: 6 additions & 15 deletions vignettes/articles/advanced-pool.Rmd
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Advanced usage"
desc: >
This article discusses how to customize your pool and how to handle
This article discusses how to customize your pool and how to handle
transactions.
---

Expand Down Expand Up @@ -32,17 +32,11 @@ First, let's get to know our Pool object:
```{r}
library(pool)
pool <- dbPool(
drv = RMySQL::MySQL(),
dbname = "shinydemo",
host = "shiny-demo.csa7qlmguqrf.us-east-1.rds.amazonaws.com",
username = "guest",
password = "guest"
)
pool <- dbPool(RSQLite::SQLite(), dbname = demoDb())
pool
```

As you can see, printing gives you basic information about your pool. This can be useful to learn how many connections you have open (both free/idle and in use).
As you can see, printing gives you basic information about your pool. This can be useful to learn how many connections you have open (both free/idle and in use).

But for this section, let's turn our attention to other parameters that you can pass to `dbPool()`: `minSize`, `maxSize`, and `idleTimeout`.

Expand All @@ -59,11 +53,8 @@ library(DBI)
library(pool)
pool <- dbPool(
drv = RMySQL::MySQL(),
dbname = "shinydemo",
host = "shiny-demo.csa7qlmguqrf.us-east-1.rds.amazonaws.com",
username = "guest",
password = "guest",
RSQLite::SQLite(),
dbname = demoDb(),
minSize = 10,
idleTimeout = 60 * 60
)
Expand All @@ -73,7 +64,7 @@ poolClose(pool)

## Transactions

So far, we've recommended you always use the pool object directly when you need to query the database. There's one challenge where this is not possible: transactions. Because for a transaction, you need to have access to the same connection for longer than a single query. The following will not necessary work because the pool might give you a different connection for each
So far, we've recommended you always use the pool object directly when you need to query the database. There's one challenge where this is not possible: transactions. Because for a transaction, you need to have access to the same connection for longer than a single query. The following will not necessary work because the pool might give you a different connection for each

```{r}
#| eval: false
Expand Down
Loading

0 comments on commit f3b0cfa

Please sign in to comment.