tests/testthat/test-driver-dbi.R

context("DBI")

## Default will find binary support in SQLite:
test_that("binary detection", {
  skip_if_not_installed("RSQLite")

  dr <- driver_dbi("data", "keys", RSQLite::SQLite(), ":memory:")
  on.exit(dr$destroy())
  expect_true(dr$binary)

  expect_true(dbi_use_binary(dr$con, "data", NULL))
  expect_true(dbi_use_binary(dr$con, "data", TRUE))
  expect_error(dbi_use_binary(dr$con, "data", FALSE),
               "storage conflicts")

  expect_true(driver_dbi("data", "keys", dr$con)$binary)
  expect_true(driver_dbi("data", "keys", dr$con, binary = TRUE)$binary)
  expect_error(driver_dbi("data", "keys", dr$con, binary = FALSE),
               "storage conflicts")

  dr_s <- driver_dbi("data_s", "key_s", RSQLite::SQLite(), ":memory:", FALSE)
  on.exit(dr_s$destroy(), add = TRUE)
  expect_false(dr_s$binary)

  expect_false(dbi_use_binary(dr_s$con, "data_s", NULL))
  expect_false(dbi_use_binary(dr_s$con, "data_s", FALSE))
  expect_error(dbi_use_binary(dr_s$con, "data_s", TRUE), "storage conflicts")

  expect_false(driver_dbi("data_s", "keys_s", dr_s$con)$binary)
  expect_false(driver_dbi("data_s", "keys_s", dr_s$con, binary = FALSE)$binary)
  expect_error(driver_dbi("data_s", "keys_s", dr_s$con, binary = TRUE),
               "storage conflicts")
})

test_that("connect, reconnect", {
  skip_if_not_installed("RSQLite")
  path <- tempfile()
  dr <- driver_dbi("data", "keys", RSQLite::SQLite(), path)
  on.exit(dr$destroy())
  st <- storr(dr)

  st$set("foo", "bar")
  expect_equal(st$get("foo"), "bar")

  dr$disconnect()
  expect_null(dr$con)
  expect_error(st$get("foo"))

  dr$reconnect()
  expect_equal(st$get("foo"), "bar")

  dr2 <- driver_dbi("data", "keys", dr$con, NULL)
  st2 <- storr(dr2)
  expect_equal(st2$get("foo"), "bar")
  expect_error(dr2$reconnect(), "Cannot reconnect to this database")

  expect_error(driver_dbi("data", "keys", dr$con, ":memory:"),
               "Cannot specify arguments when passing a connection object")
})

test_that("missing data column", {
  skip_if_not_installed("RSQLite")
  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))
  st <- storr_dbi("data", "keys", con)

  tbl_data <- "data"
  data_type <- "string"
  sql <- c(sprintf("CREATE TABLE %s", tbl_data),
           "(hash STRING PRIMARY KEY NOT NULL,",
           sprintf("data %s NOT NULL)", data_type))
  DBI::dbExecute(con, sprintf("DROP TABLE %s", tbl_data))
  DBI::dbExecute(con, paste(sql, collapse = " "))

  expect_error(storr_dbi("data", "keys", con),
               "Did not find 'value' column", fixed = TRUE)
})

test_that("storr", {
  skip_if_not_installed("RSQLite")

  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))

  st <- storr_dbi("data", "keys", con)
  expect_is(st, "storr")
  expect_equal(st$driver$type(), "DBI/SQLiteConnection")
})

test_that("binary support detection", {
  skip_if_not_installed("mockr")
  ## These can be run without any package support:
  expect_false(dbi_supports_binary(NULL))
  expect_true(dbi_supports_binary(structure(TRUE, class = "SQLiteConnection")))

  skip_if_not_installed("RSQLite")
  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))

  ## These are pretty easy:
  mockr::with_mock(dbi_supports_binary = function(...) TRUE, {
    expect_true(dbi_use_binary(con, "data", NULL))
    expect_true(dbi_use_binary(con, "data", TRUE))
    expect_false(dbi_use_binary(con, "data", FALSE))
  })

  ## Behaviour when the driver does not support binary:
  ##
  ## TODO: this does not get picked up by covr!?
  mockr::with_mock(dbi_supports_binary = function(...) FALSE, {
    expect_error(dbi_use_binary(con, "data", TRUE),
                 "Binary storage requested but storage driver does")
    expect_false(dbi_use_binary(con, "data", NULL))
    expect_false(dbi_use_binary(con, "data", FALSE))
  })
})

test_that("non-binary storage", {
  skip_if_not_installed("RSQLite")

  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))

  st <- storr_dbi("data", "keys", con, binary = FALSE)
  x <- runif(10)
  h <- st$hash_object(x)

  st$set("foo", x)
  expect_equal(st$list_hashes(), h)

  expect_equal(st$get_value(h, FALSE), x)

  st$mset(c("a", "b"), list(1, 2))
  expect_equal(st$mget(c("a", "b")), list(1, 2))
})

test_that("unknown dialects", {
  expect_error(driver_dbi_dialect(NULL),
               "Unsupported SQL driver")
})

test_that("old postgres", {
  skip_if_not_installed("mockr")
  con <- structure(list(), class = "PqConnection")
  mockr::with_mock(
    pg_server_version = function(con) numeric_version("9.4.0"),
    expect_error(driver_dbi_dialect(con),
                 "Version 9.4.0 of postgresql server is not supported"))
  mockr::with_mock(
    pg_server_version = function(con) numeric_version("9.5.0"),
    expect_equal(driver_dbi_dialect(con), "postgresql"))
})


test_that("postgres version", {
  skip_if_no_postgres()
  con <- DBI::dbConnect(RPostgres::Postgres())
  on.exit(DBI::dbDisconnect(con))
  v <- pg_server_version(con)
  expect_is(v, "numeric_version")
})

test_that("parse postgres version works for known cases", {
  expect_equal(pg_server_version_parse("90600"), numeric_version("9.6.0"))
  expect_equal(pg_server_version_parse("90209"), numeric_version("9.2.9"))
  expect_equal(pg_server_version_parse("100000"), numeric_version("10.0"))
  expect_equal(pg_server_version_parse("100004"), numeric_version("10.4"))
})

test_that("operations with quoted keys: scalar", {
  skip_if_not_installed("RSQLite")
  dkey <- '"x"'
  skey <- "'x'"
  dvalue <- '"double"'
  svalue <- "'single'"

  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))

  st <- storr_dbi("data", "keys", con, binary = FALSE)

  ## Set
  st$set(dkey, dvalue)
  st$set(skey, svalue)
  expect_equal(sort(st$list()), sort(c(dkey, skey)))

  ## Get
  expect_equal(st$get(dkey), dvalue)
  expect_equal(st$get(skey), svalue)

  ## Exists
  expect_true(st$exists(dkey))
  expect_true(st$exists(skey))

  ## Del
  expect_true(st$del(dkey))
  expect_true(st$del(skey))
})

test_that("operations with quoted keys: vector", {
  skip_if_not_installed("RSQLite")
  dkey <- '"x"'
  skey <- "'x'"
  dvalue <- '"double"'
  svalue <- "'single'"

  con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
  on.exit(DBI::dbDisconnect(con))

  st <- storr_dbi("data", "keys", con, binary = FALSE)

  st$mset(dkey, dvalue)
  expect_equal(st$mget(dkey), list(dvalue))

  st$mset(skey, svalue)
  expect_equal(st$mget(skey), list(svalue))
})

test_that("dialect generation", {
  a <- driver_dbi_sql_compat("sqlite", "foo", "bar")
  b <- driver_dbi_sql_compat("postgresql", "foo", "bar")
  expect_true(setequal(names(a), names(b)))
})

test_that("invalid dialect generation", {
  expect_error(driver_dbi_sql_compat("magic", "foo", "bar"),
               "Unsupported SQL dialect magic")
})

test_that("table names may not contain quotes", {
  mytable <- 'foo "; bar'
  expect_error(assert_valid_table_name(mytable),
               "The name of table 'mytable' may not contain quotes")
  expect_silent(assert_valid_table_name("noquotes"))
})

Try the storr package in your browser

Any scripts or data that you put into this service are public.

storr documentation built on Dec. 2, 2020, 1:06 a.m.