-
Notifications
You must be signed in to change notification settings - Fork 78
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
Date type support in DBWriteTable #351
Comments
This should have been part of issue #319 |
Thanks for raising this. Do we need to tweak |
Thanks for the hint. I think I have a solution. Add an #' @rdname SQLiteConnection-class
#' @export
setMethod("dbDataType", "SQLiteConnection", function(dbObj, obj, ...) {
dbDataType(SQLite(), obj, extended_types = dbObj@extended_types, ...)
})
#' @rdname SQLiteDriver-class
#' @export
setMethod("dbDataType", "SQLiteDriver", function(dbObj, obj, extended_types, ...) {
if (is.factor(obj)) {
return("TEXT")
}
if (is.data.frame(obj)) {
return(callNextMethod(dbObj, obj))
}
if (is.integer64(obj)) {
return("INTEGER")
}
if (extended_types && methods::is(obj, "Date")) {
return("DATE")
}
if (extended_types && methods::is(obj, "POSIXct")) {
return("TIMESTAMP")
}
if (extended_types && methods::is(obj, "hms")) {
return("TIME")
}
switch(typeof(obj),
integer = "INTEGER",
double = "REAL",
character = "TEXT",
logical = "INTEGER",
list = "BLOB",
raw = "TEXT",
stop("Unsupported type", call. = FALSE)
)
}) Test the change. library(RSQLite)
library(testthat)
#> Error in get(genname, envir = envir) : object 'testthat_print' not found
test_that("Dates and times work with dbWriteTable", {
conn <- dbConnect(RSQLite::SQLite(), ":memory:", extended_types = TRUE)
dates_and_times <- data.frame(some_date = as.Date(c("2000-01-01", "2000-02-03")),
some_datetime = .POSIXct(1:2, tz = "UTC"),
some_time = hms::hms(1:2))
dbWriteTable(conn, "dates_and_times", dates_and_times, overwrite = T)
to_match <- dbReadTable(conn, "dates_and_times")
expect_identical(lapply(to_match, class),
lapply(dates_and_times, class))
dbDisconnect(conn)
conn <- dbConnect(RSQLite::SQLite(), ":memory:", extended_types = FALSE)
dates_and_times <- data.frame(some_date = as.Date(c("2000-01-01", "2000-02-03")),
some_datetime = .POSIXct(1:2, tz = "UTC"),
some_time = hms::hms(1:2))
dbWriteTable(conn, "dates_and_times", dates_and_times, overwrite = T)
to_match <- dbReadTable(conn, "dates_and_times")
coerced_types <- list(some_date = "numeric", some_datetime = "integer", some_time = "integer")
expect_identical(lapply(to_match, class), coerced_types)
dbDisconnect(conn)
}) Created on 2021-04-01 by the reprex package (v0.3.0) Let me know what you think. |
I like it, thanks! We can borrow code from RPostgres or RMariaDB too if necessary. We could also run the |
Great! I'll work on a pulll request. Is there a development branch I should work off of or create a new branch from main? |
Thanks. Can you please branch off of main? |
I opened a PR with the changes and a simple test. I was hoping that adding the DBItest date/time checks would be as simple as
but no such luck. library(DBItest)
#> Warning: package 'DBItest' was built under R version 4.0.4
#> Error in get(genname, envir = envir) : object 'testthat_print' not found
tweaks <- tweaks(
constructor_relax_args = TRUE,
placeholder_pattern = c("?", "$1", "$name", ":name"),
date_cast = function(x) paste0("'", x, "'"),
time_cast = function(x) paste0("'", x, "'"),
timestamp_cast = function(x) paste0("'", x, "'"),
logical_return = function(x) as.integer(x),
date_typed = TRUE,
time_typed = FALSE,
timestamp_typed = FALSE
)
default_skip <- c("roundtrip_timestamp")
drv <- dblog::dblog(RSQLite::SQLite())
#> drv1 <- new("SQLiteDriver")
invisible(make_context(
new(
"DBIConnector",
.drv = drv,
.conn_args = list(dbname = tempfile("DBItest", fileext = ".sqlite"),
extended_types = TRUE)
),
tweaks = tweaks,
default_skip = default_skip
))
testthat::with_reporter(
c("location", "stop"),
DBItest::test_some("data_date_typed")
)
#> Start test: DBItest: Result: data_date_typed
#> spec-result-roundtrip.R#133:1 [success]
#> conn1 <- dbConnect(drv1, dbname = "C:\\Users\\ADAMBL~1\\AppData\\Local\\Temp\\RtmpoRH4cY\\DBItest3e5c41ac415b.sqlite",
#> extended_types = TRUE)
#> dbGetQuery(conn1, "SELECT '2015-01-01' as a, '2015-01-02' as b, '2015-01-03' as c, '2015-01-04' as d, '2015-01-05' as e, '2015-01-06' as f, '2015-01-07' as g, '2015-01-08' as h, '2015-01-09' as i, '2015-01-10' as j, '2015-01-11' as k, '2015-01-12' as l")
#> ## a b c d e f g
#> ## 1 2015-01-01 2015-01-02 2015-01-03 2015-01-04 2015-01-05 2015-01-06 2015-01-07
#> ## h i j k l
#> ## 1 2015-01-08 2015-01-09 2015-01-10 2015-01-11 2015-01-12
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [success]
#> dbGetQuery(conn1, "SELECT NULL as a, NULL as b, NULL as c, NULL as d, NULL as e, NULL as f, NULL as g, NULL as h, NULL as i, NULL as j, NULL as k, NULL as l, 1 as id UNION SELECT '2015-01-01' as a, '2015-01-02' as b, '2015-01-03' as c, '2015-01-04' as d, '2015-01-05' as e, '2015-01-06' as f, '2015-01-07' as g, '2015-01-08' as h, '2015-01-09' as i, '2015-01-10' as j, '2015-01-11' as k, '2015-01-12' as l, 2 as id")
#> ## a b c d e f g
#> ## 1 <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> ## 2 2015-01-01 2015-01-02 2015-01-03 2015-01-04 2015-01-05 2015-01-06 2015-01-07
#> ## h i j k l id
#> ## 1 <NA> <NA> <NA> <NA> <NA> 1
#> ## 2 2015-01-08 2015-01-09 2015-01-10 2015-01-11 2015-01-12 2
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> dbGetQuery(conn1, "SELECT '2015-01-01' as a, '2015-01-02' as b, '2015-01-03' as c, '2015-01-04' as d, '2015-01-05' as e, '2015-01-06' as f, '2015-01-07' as g, '2015-01-08' as h, '2015-01-09' as i, '2015-01-10' as j, '2015-01-11' as k, '2015-01-12' as l, 1 as id UNION SELECT NULL as a, NULL as b, NULL as c, NULL as d, NULL as e, NULL as f, NULL as g, NULL as h, NULL as i, NULL as j, NULL as k, NULL as l, 2 as id")
#> ## a b c d e f g
#> ## 1 <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> ## 2 2015-01-01 2015-01-02 2015-01-03 2015-01-04 2015-01-05 2015-01-06 2015-01-07
#> ## h i j k l id
#> ## 1 <NA> <NA> <NA> <NA> <NA> 2
#> ## 2 2015-01-08 2015-01-09 2015-01-10 2015-01-11 2015-01-12 1
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [failure]
#> spec-result-roundtrip.R#137:1 [success]
#> spec-result-roundtrip.R#137:1 [success]
#> dbDisconnect(conn1)
#> spec-result-roundtrip.R#137:1 [success]
#> End test: DBItest: Result: data_date_typed
#>
#> Test failed: 'DBItest: Result: data_date_typed'
#> * spec-result-roundtrip.R:137: rows[1L, 1L] not identical to structure(16436, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 2L] not identical to structure(16437, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 3L] not identical to structure(16438, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 4L] not identical to structure(16439, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 5L] not identical to structure(16440, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 6L] not identical to structure(16441, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 7L] not identical to structure(16442, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 8L] not identical to structure(16443, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 9L] not identical to structure(16444, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 10L] not identical to structure(16445, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 11L] not identical to structure(16446, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 12L] not identical to structure(16447, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 1L] not identical to structure(16436, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 2L] not identical to structure(16437, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 3L] not identical to structure(16438, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 4L] not identical to structure(16439, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 5L] not identical to structure(16440, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 6L] not identical to structure(16441, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 7L] not identical to structure(16442, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 8L] not identical to structure(16443, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 9L] not identical to structure(16444, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 10L] not identical to structure(16445, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 11L] not identical to structure(16446, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 12L] not identical to structure(16447, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 1L] not identical to structure(16436, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 2L] not identical to structure(16437, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 3L] not identical to structure(16438, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 4L] not identical to structure(16439, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 5L] not identical to structure(16440, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 6L] not identical to structure(16441, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 7L] not identical to structure(16442, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 8L] not identical to structure(16443, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 9L] not identical to structure(16444, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 10L] not identical to structure(16445, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 11L] not identical to structure(16446, class = "Date").
#> Types not compatible: character is not double
#> * spec-result-roundtrip.R:137: rows[1L, 12L] not identical to structure(16447, class = "Date").
#> Types not compatible: character is not double Created on 2021-04-02 by the reprex package (v0.3.0) I'm a little lost about how to debug this even with the guidance here. |
Thanks. The DBItest invocation looks good. We can skip the failing tests for now (by adding them to |
I agree it's still difficult to interpret these failures. In this case, results are expected to come back as a date but don't; I don't see how to fix this for this particular test, so we may well end up leaving the skip. |
I think I've made some progress and learned a little more about the DBItest package. I think that we want to use the appropriate cast functions in tweaks.
The problem is that this SQL does not return a date library(RSQLite)
con <- dbConnect(SQLite(), extended_types = TRUE)
tibble::tibble(dbGetQuery(con, "SELECT DATE('now') as a_date"))
#> # A tibble: 1 x 1
#> a_date
#> <chr>
#> 1 2021-04-08 Created on 2021-04-08 by the reprex package (v0.3.0) Clearly |
Sorry, missed that. The type assignment might happen around here: https://github.com/r-dbi/RSQLite/pull/333/files#diff-1c0fcdd98b173ac09576b9c81e81e7c14985dfeb1f11dd1e99f67b6575b728a5. It looks like we have a branch (if you scroll a bit to the top). In fact, we get library(RSQLite)
con <- dbConnect(SQLite(), extended_types = TRUE)
dbWriteTable(con, "test", data.frame(date = Sys.Date()))
str(dbReadTable(con, "test"))
#> 'data.frame': 1 obs. of 1 variable:
#> $ date: Date, format: "2021-08-21" Created on 2021-08-21 by the reprex package (v2.0.1) On the other hand, the SQL |
Thank you very much for adding Date support in RSQLite! RSQLite support Date typed columns when tables are created using SQL. However when tables are created from dataframes using dbWriteTable Date types are converted to numbers. My expectation is that when creating a SQLite table from a dataframe with
dbWriteTable
that Date types would be preserved and not converted to numbers.Created on 2021-03-16 by the reprex package (v0.3.0)
Session info
The text was updated successfully, but these errors were encountered: