@@ -1053,3 +1053,99 @@ test_that("backendDuckdb - re-initialization with new data", {
10531053 # Verify connection was reused (not a new connection)
10541054 expect_true(! is.null(backend $ private $ con ))
10551055})
1056+
1057+ test_that(" backendDuckDB() auto mode switches to server in preRenderHook" , {
1058+ skip_if_not_installed(" arrow" )
1059+ skip_if_not_installed(" duckdb" )
1060+ skip_if_not_installed(" DBI" )
1061+
1062+ data <- data.frame (x = c(1 , 2 ), y = c(" a" , " b" ))
1063+ tbl <- reactable(data , backend = backendDuckDB())
1064+
1065+ # preRenderHook should be set for auto mode
1066+ expect_true(! is.null(tbl $ preRenderHook ))
1067+
1068+ # Outside Shiny, preRenderHook keeps client mode (no changes)
1069+ tbl2 <- tbl $ preRenderHook(tbl )
1070+ expect_identical(tbl2 , tbl )
1071+ expect_equal(getAttrib(tbl2 , " backend" ), " duckdb" )
1072+ expect_true(! is.null(getAttrib(tbl2 , " arrowData" )))
1073+ expect_null(getAttrib(tbl2 , " dataURL" ))
1074+
1075+ # Inside Shiny, preRenderHook should switch to server mode
1076+ registeredURL <- NULL
1077+ mockShinySession <- new.env(parent = emptyenv())
1078+ mockShinySession $ userData <- new.env(parent = emptyenv())
1079+ mockShinySession $ registerDataObj <- function (name , data , filterFunc ) {
1080+ registeredURL <<- paste0(" /session/" , name )
1081+ registeredURL
1082+ }
1083+ local_mocked_bindings(
1084+ getDefaultReactiveDomain = function () mockShinySession ,
1085+ getCurrentOutputInfo = function (session ) list (name = " test_table" ),
1086+ .package = " shiny"
1087+ )
1088+ tbl3 <- tbl $ preRenderHook(tbl )
1089+
1090+ # Should have switched to server mode: dataURL set, client-mode props cleared
1091+ expect_equal(getAttrib(tbl3 , " dataURL" ), registeredURL )
1092+ expect_null(getAttrib(tbl3 , " arrowData" ))
1093+ expect_null(getAttrib(tbl3 , " parquetId" ))
1094+ expect_null(getAttrib(tbl3 , " backend" ))
1095+ # Should have server row counts
1096+ expect_equal(getAttrib(tbl3 , " serverRowCount" ), 2 )
1097+ expect_null(getAttrib(tbl3 , " serverMaxRowCount" ))
1098+ # Should have registered data URL with the session
1099+ expect_equal(registeredURL , " /session/test_table" )
1100+ # Should have stored backend and data in session$userData
1101+ serverDataStore <- mockShinySession $ userData [[" __reactable__test_table" ]]
1102+ expect_true(! is.null(serverDataStore ))
1103+ expect_s3_class(serverDataStore $ value $ backend , " reactable_backendDuckdb" )
1104+ expect_equal(nrow(serverDataStore $ value $ data ), 2 )
1105+ expect_false(" _reactable_rowid" %in% colnames(serverDataStore $ value $ data ))
1106+ # Should have removed client-mode dependencies (duckdb-wasm, parquet sidecar)
1107+ depNames <- vapply(tbl3 $ dependencies , function (d ) d $ name , character (1 ))
1108+ expect_false(" duckdb-wasm" %in% depNames )
1109+ expect_false(any(startsWith(depNames , " reactable-parquet-" )))
1110+ })
1111+
1112+ test_that(" backendDuckDB(format = 'parquet') auto mode removes parquet dependency" , {
1113+ skip_if_not_installed(" arrow" )
1114+ skip_if_not_installed(" duckdb" )
1115+ skip_if_not_installed(" DBI" )
1116+
1117+ data <- data.frame (x = c(1 , 2 ), y = c(" a" , " b" ))
1118+ tbl <- reactable(data , backend = backendDuckDB(format = " parquet" ))
1119+
1120+ # Parquet format should have parquet sidecar dependency in client mode
1121+ depNames <- vapply(tbl $ dependencies , function (d ) d $ name , character (1 ))
1122+ expect_true(any(startsWith(depNames , " reactable-parquet-" )))
1123+
1124+ # Inside Shiny, preRenderHook should switch to server mode and remove parquet dep
1125+ registeredURL <- NULL
1126+ mockShinySession <- new.env(parent = emptyenv())
1127+ mockShinySession $ userData <- new.env(parent = emptyenv())
1128+ mockShinySession $ registerDataObj <- function (name , data , filterFunc ) {
1129+ registeredURL <<- paste0(" /session/" , name )
1130+ registeredURL
1131+ }
1132+ local_mocked_bindings(
1133+ getDefaultReactiveDomain = function () mockShinySession ,
1134+ getCurrentOutputInfo = function (session ) list (name = " test_table2" ),
1135+ .package = " shiny"
1136+ )
1137+ tbl2 <- tbl $ preRenderHook(tbl )
1138+
1139+ depNames2 <- vapply(tbl2 $ dependencies , function (d ) d $ name , character (1 ))
1140+ expect_false(" duckdb-wasm" %in% depNames2 )
1141+ expect_false(any(startsWith(depNames2 , " reactable-parquet-" )))
1142+ })
1143+
1144+ test_that(" backendDuckDB(mode = 'client') has no preRenderHook" , {
1145+ skip_if_not_installed(" arrow" )
1146+
1147+ data <- data.frame (x = c(1 , 2 ), y = c(" a" , " b" ))
1148+ tbl <- reactable(data , backend = backendDuckDB(mode = " client" ))
1149+ # preRenderHook should not be set when user explicitly chose client mode
1150+ expect_null(tbl $ preRenderHook )
1151+ })
0 commit comments